13d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
23d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * net/drivers/team/team.c - Network team device driver
33d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
43d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko *
53d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * This program is free software; you can redistribute it and/or modify
63d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * it under the terms of the GNU General Public License as published by
73d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * the Free Software Foundation; either version 2 of the License, or
83d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * (at your option) any later version.
93d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/kernel.h>
123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/types.h>
133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/module.h>
143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/init.h>
153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/slab.h>
163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/rcupdate.h>
173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/errno.h>
183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/ctype.h>
193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/notifier.h>
203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/netdevice.h>
2187002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko#include <linux/if_vlan.h>
223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/if_arp.h>
233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/socket.h>
243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/etherdevice.h>
253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/rtnetlink.h>
263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <net/rtnetlink.h>
273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <net/genetlink.h>
283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <net/netlink.h>
293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#include <linux/if_team.h>
303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#define DRV_NAME "team"
323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/**********
353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Helpers
363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko **********/
373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct team_port *team_port_get_rcu(const struct net_device *dev)
413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port = rcu_dereference(dev->rx_handler_data);
433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return team_port_exists(dev) ? port : NULL;
453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct team_port *team_port_get_rtnl(const struct net_device *dev)
483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port = rtnl_dereference(dev->rx_handler_data);
503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return team_port_exists(dev) ? port : NULL;
523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Since the ability to change mac address for open port device is tested in
563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * team_port_add, this function can be called without control of return value
573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int __set_port_mac(struct net_device *port_dev,
593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			  const unsigned char *dev_addr)
603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sockaddr addr;
623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	memcpy(addr.sa_data, dev_addr, ETH_ALEN);
643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	addr.sa_family = ARPHRD_ETHER;
653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return dev_set_mac_address(port_dev, &addr);
663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoint team_port_set_orig_mac(struct team_port *port)
693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return __set_port_mac(port->dev, port->orig.dev_addr);
713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoint team_port_set_team_mac(struct team_port *port)
743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return __set_port_mac(port->dev, port->team->dev->dev_addr);
763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoEXPORT_SYMBOL(team_port_set_team_mac);
783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*******************
813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Options handling
823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko *******************/
833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
84358b838291f618278080bbed435b755f9b46748eJiri Pirkostruct team_option *__team_find_option(struct team *team, const char *opt_name)
85358b838291f618278080bbed435b755f9b46748eJiri Pirko{
86358b838291f618278080bbed435b755f9b46748eJiri Pirko	struct team_option *option;
87358b838291f618278080bbed435b755f9b46748eJiri Pirko
88358b838291f618278080bbed435b755f9b46748eJiri Pirko	list_for_each_entry(option, &team->option_list, list) {
89358b838291f618278080bbed435b755f9b46748eJiri Pirko		if (strcmp(option->name, opt_name) == 0)
90358b838291f618278080bbed435b755f9b46748eJiri Pirko			return option;
91358b838291f618278080bbed435b755f9b46748eJiri Pirko	}
92358b838291f618278080bbed435b755f9b46748eJiri Pirko	return NULL;
93358b838291f618278080bbed435b755f9b46748eJiri Pirko}
94358b838291f618278080bbed435b755f9b46748eJiri Pirko
95b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkoint __team_options_register(struct team *team,
96b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			    const struct team_option *option,
97b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			    size_t option_count)
983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
1002bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko	struct team_option **dst_opts;
101358b838291f618278080bbed435b755f9b46748eJiri Pirko	int err;
1023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1032bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko	dst_opts = kzalloc(sizeof(struct team_option *) * option_count,
1042bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko			   GFP_KERNEL);
1052bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko	if (!dst_opts)
1062bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko		return -ENOMEM;
107358b838291f618278080bbed435b755f9b46748eJiri Pirko	for (i = 0; i < option_count; i++, option++) {
108358b838291f618278080bbed435b755f9b46748eJiri Pirko		if (__team_find_option(team, option->name)) {
109358b838291f618278080bbed435b755f9b46748eJiri Pirko			err = -EEXIST;
110358b838291f618278080bbed435b755f9b46748eJiri Pirko			goto rollback;
111358b838291f618278080bbed435b755f9b46748eJiri Pirko		}
112f8a15af093b19b86d56933c8757cee298d0f32a8Jiri Pirko		dst_opts[i] = kmemdup(option, sizeof(*option), GFP_KERNEL);
113f8a15af093b19b86d56933c8757cee298d0f32a8Jiri Pirko		if (!dst_opts[i]) {
114358b838291f618278080bbed435b755f9b46748eJiri Pirko			err = -ENOMEM;
115358b838291f618278080bbed435b755f9b46748eJiri Pirko			goto rollback;
116358b838291f618278080bbed435b755f9b46748eJiri Pirko		}
117358b838291f618278080bbed435b755f9b46748eJiri Pirko	}
118358b838291f618278080bbed435b755f9b46748eJiri Pirko
119b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	for (i = 0; i < option_count; i++) {
120b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		dst_opts[i]->changed = true;
121b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		dst_opts[i]->removed = false;
122358b838291f618278080bbed435b755f9b46748eJiri Pirko		list_add_tail(&dst_opts[i]->list, &team->option_list);
123b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	}
124358b838291f618278080bbed435b755f9b46748eJiri Pirko
1252bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko	kfree(dst_opts);
126358b838291f618278080bbed435b755f9b46748eJiri Pirko	return 0;
127358b838291f618278080bbed435b755f9b46748eJiri Pirko
128358b838291f618278080bbed435b755f9b46748eJiri Pirkorollback:
129358b838291f618278080bbed435b755f9b46748eJiri Pirko	for (i = 0; i < option_count; i++)
130358b838291f618278080bbed435b755f9b46748eJiri Pirko		kfree(dst_opts[i]);
131358b838291f618278080bbed435b755f9b46748eJiri Pirko
1322bba19fff8d09bf19df5d5e2de7188d65de67c3eJiri Pirko	kfree(dst_opts);
133358b838291f618278080bbed435b755f9b46748eJiri Pirko	return err;
1343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
135358b838291f618278080bbed435b755f9b46748eJiri Pirko
136b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic void __team_options_mark_removed(struct team *team,
137b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					const struct team_option *option,
138b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					size_t option_count)
139b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko{
140b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	int i;
141b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko
142b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	for (i = 0; i < option_count; i++, option++) {
143b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		struct team_option *del_opt;
1443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
145b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		del_opt = __team_find_option(team, option->name);
146b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (del_opt) {
147b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			del_opt->changed = true;
148b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			del_opt->removed = true;
149b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		}
150b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	}
151b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko}
1523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __team_options_unregister(struct team *team,
154358b838291f618278080bbed435b755f9b46748eJiri Pirko				      const struct team_option *option,
1553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				      size_t option_count)
1563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
1573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
1583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
159358b838291f618278080bbed435b755f9b46748eJiri Pirko	for (i = 0; i < option_count; i++, option++) {
160358b838291f618278080bbed435b755f9b46748eJiri Pirko		struct team_option *del_opt;
161358b838291f618278080bbed435b755f9b46748eJiri Pirko
162358b838291f618278080bbed435b755f9b46748eJiri Pirko		del_opt = __team_find_option(team, option->name);
163358b838291f618278080bbed435b755f9b46748eJiri Pirko		if (del_opt) {
164358b838291f618278080bbed435b755f9b46748eJiri Pirko			list_del(&del_opt->list);
165358b838291f618278080bbed435b755f9b46748eJiri Pirko			kfree(del_opt);
166358b838291f618278080bbed435b755f9b46748eJiri Pirko		}
167358b838291f618278080bbed435b755f9b46748eJiri Pirko	}
1683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
1693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
170b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic void __team_options_change_check(struct team *team);
171b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko
172b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkoint team_options_register(struct team *team,
173b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			  const struct team_option *option,
174b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			  size_t option_count)
175b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko{
176b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	int err;
177b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko
178b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = __team_options_register(team, option, option_count);
179b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	if (err)
180b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		return err;
181b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	__team_options_change_check(team);
182b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	return 0;
183b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko}
184b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri PirkoEXPORT_SYMBOL(team_options_register);
185b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko
186358b838291f618278080bbed435b755f9b46748eJiri Pirkovoid team_options_unregister(struct team *team,
187358b838291f618278080bbed435b755f9b46748eJiri Pirko			     const struct team_option *option,
1883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			     size_t option_count)
1893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
190b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	__team_options_mark_removed(team, option, option_count);
191b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	__team_options_change_check(team);
1923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_options_unregister(team, option, option_count);
1933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
1943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoEXPORT_SYMBOL(team_options_unregister);
1953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_option_get(struct team *team, struct team_option *option,
1973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   void *arg)
1983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
1993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return option->getter(team, arg);
2003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_option_set(struct team *team, struct team_option *option,
2033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   void *arg)
2043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
2063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = option->setter(team, arg);
2083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
2093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return err;
2103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
211b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	option->changed = true;
212b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	__team_options_change_check(team);
2133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
2143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/****************
2173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Mode handling
2183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ****************/
2193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic LIST_HEAD(mode_list);
2213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic DEFINE_SPINLOCK(mode_list_lock);
2223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct team_mode *__find_mode(const char *kind)
2243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_mode *mode;
2263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(mode, &mode_list, list) {
2283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (strcmp(mode->kind, kind) == 0)
2293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return mode;
2303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
2313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return NULL;
2323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic bool is_good_mode_name(const char *name)
2353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	while (*name != '\0') {
2373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
2383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return false;
2393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		name++;
2403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
2413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return true;
2423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoint team_mode_register(struct team_mode *mode)
2453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err = 0;
2473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!is_good_mode_name(mode->kind) ||
2493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	    mode->priv_size > TEAM_MODE_PRIV_SIZE)
2503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
2513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_lock(&mode_list_lock);
2523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (__find_mode(mode->kind)) {
2533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = -EEXIST;
2543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto unlock;
2553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
2563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_add_tail(&mode->list, &mode_list);
2573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkounlock:
2583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_unlock(&mode_list_lock);
2593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
2603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoEXPORT_SYMBOL(team_mode_register);
2623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoint team_mode_unregister(struct team_mode *mode)
2643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_lock(&mode_list_lock);
2663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_del_init(&mode->list);
2673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_unlock(&mode_list_lock);
2683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
2693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoEXPORT_SYMBOL(team_mode_unregister);
2713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct team_mode *team_mode_get(const char *kind)
2733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_mode *mode;
2753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_lock(&mode_list_lock);
2773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	mode = __find_mode(kind);
2783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!mode) {
2793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		spin_unlock(&mode_list_lock);
2803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		request_module("team-mode-%s", kind);
2813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		spin_lock(&mode_list_lock);
2823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		mode = __find_mode(kind);
2833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
2843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (mode)
2853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!try_module_get(mode->owner))
2863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			mode = NULL;
2873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	spin_unlock(&mode_list_lock);
2893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return mode;
2903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_mode_put(const struct team_mode *mode)
2933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	module_put(mode->owner);
2953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
2963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
2973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic bool team_dummy_transmit(struct team *team, struct sk_buff *skb)
2983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
2993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_kfree_skb_any(skb);
3003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return false;
3013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
3023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkorx_handler_result_t team_dummy_receive(struct team *team,
3043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				       struct team_port *port,
3053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				       struct sk_buff *skb)
3063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
3073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return RX_HANDLER_ANOTHER;
3083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
3093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_adjust_ops(struct team *team)
3113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
3123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	/*
3133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * To avoid checks in rx/tx skb paths, ensure here that non-null and
3143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * correct ops are always set.
3153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 */
3163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (list_empty(&team->port_list) ||
3183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	    !team->mode || !team->mode->ops->transmit)
3193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->ops.transmit = team_dummy_transmit;
3203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	else
3213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->ops.transmit = team->mode->ops->transmit;
3223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (list_empty(&team->port_list) ||
3243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	    !team->mode || !team->mode->ops->receive)
3253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->ops.receive = team_dummy_receive;
3263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	else
3273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->ops.receive = team->mode->ops->receive;
3283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
3293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
3313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * We can benefit from the fact that it's ensured no port is present
3323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * at the time of mode change. Therefore no packets are in fly so there's no
3333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * need to set mode operations in any special way.
3343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
3353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int __team_change_mode(struct team *team,
3363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			      const struct team_mode *new_mode)
3373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
3383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	/* Check if mode was previously set and do cleanup if so */
3393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (team->mode) {
3403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		void (*exit_op)(struct team *team) = team->ops.exit;
3413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		/* Clear ops area so no callback is called any longer */
3433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		memset(&team->ops, 0, sizeof(struct team_mode_ops));
3443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_adjust_ops(team);
3453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (exit_op)
3473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			exit_op(team);
3483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_mode_put(team->mode);
3493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->mode = NULL;
3503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		/* zero private data area */
3513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		memset(&team->mode_priv, 0,
3523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		       sizeof(struct team) - offsetof(struct team, mode_priv));
3533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
3543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!new_mode)
3563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return 0;
3573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (new_mode->ops->init) {
3593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		int err;
3603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = new_mode->ops->init(team);
3623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (err)
3633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return err;
3643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
3653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->mode = new_mode;
3673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	memcpy(&team->ops, new_mode->ops, sizeof(struct team_mode_ops));
3683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_adjust_ops(team);
3693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
3713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
3723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_change_mode(struct team *team, const char *kind)
3743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
3753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_mode *new_mode;
3763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net_device *dev = team->dev;
3773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
3783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!list_empty(&team->port_list)) {
3803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "No ports can be present during mode change\n");
3813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EBUSY;
3823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
3833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (team->mode && strcmp(team->mode->kind, kind) == 0) {
3853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Unable to change to the same mode the team is in\n");
3863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
3873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
3883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	new_mode = team_mode_get(kind);
3903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!new_mode) {
3913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Mode \"%s\" not found\n", kind);
3923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
3933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
3943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
3953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = __team_change_mode(team, new_mode);
3963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
3973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Failed to change to mode \"%s\"\n", kind);
3983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_mode_put(new_mode);
3993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return err;
4003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
4013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_info(dev, "Mode changed to \"%s\"\n", kind);
4033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
4043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
4053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/************************
4083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Rx path frame handler
4093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ************************/
4103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/* note: already called with rcu_read_lock */
4123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
4133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
4143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sk_buff *skb = *pskb;
4153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
4163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team;
4173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rx_handler_result_t res;
4183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	skb = skb_share_check(skb, GFP_ATOMIC);
4203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!skb)
4213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return RX_HANDLER_CONSUMED;
4223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	*pskb = skb;
4243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port = team_port_get_rcu(skb->dev);
4263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team = port->team;
4273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	res = team->ops.receive(team, port, skb);
4293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (res == RX_HANDLER_ANOTHER) {
4303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct team_pcpu_stats *pcpu_stats;
4313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats = this_cpu_ptr(team->pcpu_stats);
4333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		u64_stats_update_begin(&pcpu_stats->syncp);
4343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats->rx_packets++;
4353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats->rx_bytes += skb->len;
4363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (skb->pkt_type == PACKET_MULTICAST)
4373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			pcpu_stats->rx_multicast++;
4383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		u64_stats_update_end(&pcpu_stats->syncp);
4393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		skb->dev = team->dev;
4413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	} else {
4423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		this_cpu_inc(team->pcpu_stats->rx_dropped);
4433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
4443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return res;
4463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
4473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/****************
4503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Port handling
4513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ****************/
4523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic bool team_port_find(const struct team *team,
4543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   const struct team_port *port)
4553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
4563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *cur;
4573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(cur, &team->port_list, list)
4593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (cur == port)
4603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return true;
4613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return false;
4623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
4633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
4653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Add/delete port to the team port list. Write guarded by rtnl_lock.
4663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Takes care of correct port->index setup (might be racy).
4673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
4683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_port_list_add_port(struct team *team,
4693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				    struct team_port *port)
4703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
4713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->index = team->port_count++;
4723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	hlist_add_head_rcu(&port->hlist,
4733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   team_port_index_hash(team, port->index));
4743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_add_tail_rcu(&port->list, &team->port_list);
4753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
4763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __reconstruct_port_hlist(struct team *team, int rm_index)
4783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
4793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
4803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
4813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	for (i = rm_index + 1; i < team->port_count; i++) {
4833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		port = team_get_port_by_index(team, i);
4843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		hlist_del_rcu(&port->hlist);
4853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		port->index--;
4863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		hlist_add_head_rcu(&port->hlist,
4873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				   team_port_index_hash(team, port->index));
4883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
4893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
4903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_port_list_del_port(struct team *team,
4923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				   struct team_port *port)
4933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
4943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int rm_index = port->index;
4953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
4963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	hlist_del_rcu(&port->hlist);
4973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_del_rcu(&port->list);
4983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__reconstruct_port_hlist(team, rm_index);
4993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->port_count--;
5003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
5013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
5033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			    NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
5043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			    NETIF_F_HIGHDMA | NETIF_F_LRO)
5053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __team_compute_features(struct team *team)
5073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
5083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
5093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	u32 vlan_features = TEAM_VLAN_FEATURES;
5103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	unsigned short max_hard_header_len = ETH_HLEN;
5113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(port, &team->port_list, list) {
5133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		vlan_features = netdev_increment_features(vlan_features,
5143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko					port->dev->vlan_features,
5153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko					TEAM_VLAN_FEATURES);
5163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (port->dev->hard_header_len > max_hard_header_len)
5183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			max_hard_header_len = port->dev->hard_header_len;
5193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
5203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->dev->vlan_features = vlan_features;
5223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->dev->hard_header_len = max_hard_header_len;
5233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_change_features(team->dev);
5253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
5263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_compute_features(struct team *team)
5283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
52961dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
5303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_compute_features(team);
53161dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
5323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
5333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_port_enter(struct team *team, struct team_port *port)
5353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
5363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err = 0;
5373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_hold(team->dev);
5393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->dev->priv_flags |= IFF_TEAM_PORT;
5403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (team->ops.port_enter) {
5413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = team->ops.port_enter(team, port);
5423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (err) {
5433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			netdev_err(team->dev, "Device %s failed to enter team mode\n",
5443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				   port->dev->name);
5453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto err_port_enter;
5463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
5473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
5483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
5503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_port_enter:
5523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->dev->priv_flags &= ~IFF_TEAM_PORT;
5533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_put(team->dev);
5543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
5563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
5573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_port_leave(struct team *team, struct team_port *port)
5593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
5603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (team->ops.port_leave)
5613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team->ops.port_leave(team, port);
5623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->dev->priv_flags &= ~IFF_TEAM_PORT;
5633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_put(team->dev);
5643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
5653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __team_port_change_check(struct team_port *port, bool linkup);
5673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_port_add(struct team *team, struct net_device *port_dev)
5693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
5703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net_device *dev = team->dev;
5713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
5723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	char *portname = port_dev->name;
5733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
5743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (port_dev->flags & IFF_LOOPBACK ||
5763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	    port_dev->type != ARPHRD_ETHER) {
5773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s is of an unsupported type\n",
5783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
5793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
5803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
5813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (team_port_exists(port_dev)) {
5833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s is already a port "
5843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				"of a team device\n", portname);
5853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EBUSY;
5863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
5873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (port_dev->flags & IFF_UP) {
5893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
5903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
5913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EBUSY;
5923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
5933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
5953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!port)
5963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
5973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
5983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->dev = port_dev;
5993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->team = team;
6003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->orig.mtu = port_dev->mtu;
6023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = dev_set_mtu(port_dev, dev->mtu);
6033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
6043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
6053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_set_mtu;
6063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN);
6093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = team_port_enter(team, port);
6113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
6123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s failed to enter team mode\n",
6133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
6143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_port_enter;
6153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = dev_open(port_dev);
6183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
6193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_dbg(dev, "Device %s opening failed\n",
6203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
6213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_dev_open;
6223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
62457459185a19b0246866479522b77cbb9732201d1Jiri Pirko	err = vlan_vids_add_by_dev(port_dev, dev);
62557459185a19b0246866479522b77cbb9732201d1Jiri Pirko	if (err) {
62657459185a19b0246866479522b77cbb9732201d1Jiri Pirko		netdev_err(dev, "Failed to add vlan ids to device %s\n",
62757459185a19b0246866479522b77cbb9732201d1Jiri Pirko				portname);
62857459185a19b0246866479522b77cbb9732201d1Jiri Pirko		goto err_vids_add;
62957459185a19b0246866479522b77cbb9732201d1Jiri Pirko	}
63057459185a19b0246866479522b77cbb9732201d1Jiri Pirko
6313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = netdev_set_master(port_dev, dev);
6323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
6333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s failed to set master\n", portname);
6343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_set_master;
6353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = netdev_rx_handler_register(port_dev, team_handle_frame,
6383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko					 port);
6393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err) {
6403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s failed to register rx_handler\n",
6413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
6423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_handler_register;
6433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_list_add_port(team, port);
6463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_adjust_ops(team);
6473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_compute_features(team);
6483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_port_change_check(port, !!netif_carrier_ok(port_dev));
6493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_info(dev, "Port device %s added\n", portname);
6513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
6533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_handler_register:
6553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_set_master(port_dev, NULL);
6563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_set_master:
65857459185a19b0246866479522b77cbb9732201d1Jiri Pirko	vlan_vids_del_by_dev(port_dev, dev);
65957459185a19b0246866479522b77cbb9732201d1Jiri Pirko
66057459185a19b0246866479522b77cbb9732201d1Jiri Pirkoerr_vids_add:
6613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_close(port_dev);
6623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_dev_open:
6643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_leave(team, port);
6653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_set_orig_mac(port);
6663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_port_enter:
6683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_set_mtu(port_dev, port->orig.mtu);
6693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_set_mtu:
6713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	kfree(port);
6723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
6743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
6753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_port_del(struct team *team, struct net_device *port_dev)
6773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
6783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net_device *dev = team->dev;
6793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
6803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	char *portname = port_dev->name;
6813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
6823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port = team_port_get_rtnl(port_dev);
6833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!port || !team_port_find(team, port)) {
6843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_err(dev, "Device %s does not act as a port of this team\n",
6853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   portname);
6863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOENT;
6873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
6883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
689b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	port->removed = true;
6903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_port_change_check(port, false);
6913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_list_del_port(team, port);
6923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_adjust_ops(team);
6933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_rx_handler_unregister(port_dev);
6943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_set_master(port_dev, NULL);
69557459185a19b0246866479522b77cbb9732201d1Jiri Pirko	vlan_vids_del_by_dev(port_dev, dev);
6963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_close(port_dev);
6973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_leave(team, port);
6983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_port_set_orig_mac(port);
6993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev_set_mtu(port_dev, port->orig.mtu);
7003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	synchronize_rcu();
7013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	kfree(port);
7023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netdev_info(dev, "Port device %s removed\n", portname);
7033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_compute_features(team);
7043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
7063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*****************
7103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Net device ops
7113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko *****************/
7123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic const char team_no_mode_kind[] = "*NOMODE*";
7143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_mode_option_get(struct team *team, void *arg)
7163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	const char **str = arg;
7183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	*str = team->mode ? team->mode->kind : team_no_mode_kind;
7203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
7213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_mode_option_set(struct team *team, void *arg)
7243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	const char **str = arg;
7263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return team_change_mode(team, *str);
7283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
730358b838291f618278080bbed435b755f9b46748eJiri Pirkostatic const struct team_option team_options[] = {
7313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	{
7323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.name = "mode",
7333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.type = TEAM_OPTION_TYPE_STRING,
7343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.getter = team_mode_option_get,
7353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.setter = team_mode_option_set,
7363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
7373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
7383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_init(struct net_device *dev)
7403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
7423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
743358b838291f618278080bbed435b755f9b46748eJiri Pirko	int err;
7443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->dev = dev;
74661dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_init(&team->lock);
7473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
7493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!team->pcpu_stats)
7503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
7513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
7533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		INIT_HLIST_HEAD(&team->port_hlist[i]);
7543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	INIT_LIST_HEAD(&team->port_list);
7553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_adjust_ops(team);
7573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	INIT_LIST_HEAD(&team->option_list);
759358b838291f618278080bbed435b755f9b46748eJiri Pirko	err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
760358b838291f618278080bbed435b755f9b46748eJiri Pirko	if (err)
761358b838291f618278080bbed435b755f9b46748eJiri Pirko		goto err_options_register;
7623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netif_carrier_off(dev);
7633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
765358b838291f618278080bbed435b755f9b46748eJiri Pirko
766358b838291f618278080bbed435b755f9b46748eJiri Pirkoerr_options_register:
767358b838291f618278080bbed435b755f9b46748eJiri Pirko	free_percpu(team->pcpu_stats);
768358b838291f618278080bbed435b755f9b46748eJiri Pirko
769358b838291f618278080bbed435b755f9b46748eJiri Pirko	return err;
7703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_uninit(struct net_device *dev)
7733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
7753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
7763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *tmp;
7773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
77861dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
7793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry_safe(port, tmp, &team->port_list, list)
7803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_port_del(team, port->dev);
7813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_change_mode(team, NULL); /* cleanup */
7833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
78461dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
7853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_destructor(struct net_device *dev)
7883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
7903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	free_percpu(team->pcpu_stats);
7923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	free_netdev(dev);
7933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
7943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
7953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_open(struct net_device *dev)
7963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
7973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netif_carrier_on(dev);
7983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
7993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_close(struct net_device *dev)
8023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	netif_carrier_off(dev);
8043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
8053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
8083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * note: already called with rcu_read_lock
8093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
8103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
8113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
8133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	bool tx_success = false;
8143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	unsigned int len = skb->len;
8153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	tx_success = team->ops.transmit(team, skb);
8173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (tx_success) {
8183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct team_pcpu_stats *pcpu_stats;
8193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats = this_cpu_ptr(team->pcpu_stats);
8213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		u64_stats_update_begin(&pcpu_stats->syncp);
8223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats->tx_packets++;
8233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		pcpu_stats->tx_bytes += len;
8243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		u64_stats_update_end(&pcpu_stats->syncp);
8253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	} else {
8263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		this_cpu_inc(team->pcpu_stats->tx_dropped);
8273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
8283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return NETDEV_TX_OK;
8303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_change_rx_flags(struct net_device *dev, int change)
8333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
8353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
8363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int inc;
8373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_lock();
8393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry_rcu(port, &team->port_list, list) {
8403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (change & IFF_PROMISC) {
8413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			inc = dev->flags & IFF_PROMISC ? 1 : -1;
8423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			dev_set_promiscuity(port->dev, inc);
8433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
8443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (change & IFF_ALLMULTI) {
8453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			inc = dev->flags & IFF_ALLMULTI ? 1 : -1;
8463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			dev_set_allmulti(port->dev, inc);
8473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
8483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
8493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_unlock();
8503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_set_rx_mode(struct net_device *dev)
8533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
8553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
8563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_lock();
8583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry_rcu(port, &team->port_list, list) {
8593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		dev_uc_sync(port->dev, dev);
8603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		dev_mc_sync(port->dev, dev);
8613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
8623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_unlock();
8633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_set_mac_address(struct net_device *dev, void *p)
8663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
8683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
8693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sockaddr *addr = p;
8703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8717ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
8723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
8733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_lock();
8743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry_rcu(port, &team->port_list, list)
8753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (team->ops.port_change_mac)
8763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			team->ops.port_change_mac(team, port);
8773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_unlock();
8783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
8793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
8803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_change_mtu(struct net_device *dev, int new_mtu)
8823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
8833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
8843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
8853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
8863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
8873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	/*
8883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * Alhough this is reader, it's guarded by team lock. It's not possible
8893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * to traverse list in reverse under rcu_read_lock
8903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 */
89161dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
8923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(port, &team->port_list, list) {
8933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = dev_set_mtu(port->dev, new_mtu);
8943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (err) {
8953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			netdev_err(dev, "Device %s failed to change mtu",
8963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				   port->dev->name);
8973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto unwind;
8983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
8993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
90061dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
9013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->mtu = new_mtu;
9033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
9053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkounwind:
9073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry_continue_reverse(port, &team->port_list, list)
9083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		dev_set_mtu(port->dev, dev->mtu);
90961dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
9103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
9123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
9133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct rtnl_link_stats64 *
9153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoteam_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
9163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
9173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
9183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_pcpu_stats *p;
9193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
9203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	u32 rx_dropped = 0, tx_dropped = 0;
9213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	unsigned int start;
9223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
9233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	for_each_possible_cpu(i) {
9253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		p = per_cpu_ptr(team->pcpu_stats, i);
9263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		do {
9273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			start = u64_stats_fetch_begin_bh(&p->syncp);
9283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			rx_packets	= p->rx_packets;
9293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			rx_bytes	= p->rx_bytes;
9303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			rx_multicast	= p->rx_multicast;
9313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			tx_packets	= p->tx_packets;
9323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			tx_bytes	= p->tx_bytes;
9333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		} while (u64_stats_fetch_retry_bh(&p->syncp, start));
9343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		stats->rx_packets	+= rx_packets;
9363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		stats->rx_bytes		+= rx_bytes;
9373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		stats->multicast	+= rx_multicast;
9383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		stats->tx_packets	+= tx_packets;
9393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		stats->tx_bytes		+= tx_bytes;
9403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		/*
9413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		 * rx_dropped & tx_dropped are u32, updated
9423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		 * without syncp protection.
9433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		 */
9443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		rx_dropped	+= p->rx_dropped;
9453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		tx_dropped	+= p->tx_dropped;
9463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
9473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	stats->rx_dropped	= rx_dropped;
9483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	stats->tx_dropped	= tx_dropped;
9493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return stats;
9503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
9513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9528e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirkostatic int team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
9533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
9543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
9553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
95687002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	int err;
9573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
95887002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	/*
95987002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	 * Alhough this is reader, it's guarded by team lock. It's not possible
96087002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	 * to traverse list in reverse under rcu_read_lock
96187002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	 */
96287002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	mutex_lock(&team->lock);
96387002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	list_for_each_entry(port, &team->port_list, list) {
96487002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko		err = vlan_vid_add(port->dev, vid);
96587002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko		if (err)
96687002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko			goto unwind;
9673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
96887002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	mutex_unlock(&team->lock);
9698e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko
9708e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko	return 0;
97187002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko
97287002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirkounwind:
97387002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	list_for_each_entry_continue_reverse(port, &team->port_list, list)
97487002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko		vlan_vid_del(port->dev, vid);
97587002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	mutex_unlock(&team->lock);
97687002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko
97787002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	return err;
9783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
9793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9808e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirkostatic int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
9813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
9823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
9833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
9843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_lock();
98687002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko	list_for_each_entry_rcu(port, &team->port_list, list)
98787002b03baabd2b8f6281ab6411ed88d24958de1Jiri Pirko		vlan_vid_del(port->dev, vid);
9883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rcu_read_unlock();
9898e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko
9908e586137e6b63af1e881b328466ab5ffbe562510Jiri Pirko	return 0;
9913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
9923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
9933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_add_slave(struct net_device *dev, struct net_device *port_dev)
9943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
9953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
9963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
9973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
99861dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
9993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = team_port_add(team, port_dev);
100061dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
10013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
10023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
10033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_del_slave(struct net_device *dev, struct net_device *port_dev)
10053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
10063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = netdev_priv(dev);
10073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
10083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
100961dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
10103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = team_port_del(team, port_dev);
101161dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
10123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
10133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
10143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1015234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirkostatic netdev_features_t team_fix_features(struct net_device *dev,
1016234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko					   netdev_features_t features)
1017234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko{
1018234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	struct team_port *port;
1019234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	struct team *team = netdev_priv(dev);
1020234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	netdev_features_t mask;
1021234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko
1022234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	mask = features;
1023234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	features &= ~NETIF_F_ONE_FOR_ALL;
1024234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	features |= NETIF_F_ALL_FOR_ALL;
1025234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko
1026234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	rcu_read_lock();
1027234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	list_for_each_entry_rcu(port, &team->port_list, list) {
1028234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko		features = netdev_increment_features(features,
1029234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko						     port->dev->features,
1030234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko						     mask);
1031234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	}
1032234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	rcu_read_unlock();
1033234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	return features;
1034234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko}
1035234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko
10363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic const struct net_device_ops team_netdev_ops = {
10373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_init		= team_init,
10383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_uninit		= team_uninit,
10393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_open		= team_open,
10403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_stop		= team_close,
10413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_start_xmit		= team_xmit,
10423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_change_rx_flags	= team_change_rx_flags,
10433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_set_rx_mode	= team_set_rx_mode,
10443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_set_mac_address	= team_set_mac_address,
10453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_change_mtu		= team_change_mtu,
10463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_get_stats64	= team_get_stats64,
10473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_vlan_rx_add_vid	= team_vlan_rx_add_vid,
10483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_vlan_rx_kill_vid	= team_vlan_rx_kill_vid,
10493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_add_slave		= team_add_slave,
10503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.ndo_del_slave		= team_del_slave,
1051234a8fd49d086f5a3debb379bfdf4e6b51f0c0e2Jiri Pirko	.ndo_fix_features	= team_fix_features,
10523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
10533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/***********************
10563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * rt netlink interface
10573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ***********************/
10583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_setup(struct net_device *dev)
10603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
10613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	ether_setup(dev);
10623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->netdev_ops = &team_netdev_ops;
10643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->destructor	= team_destructor;
10653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->tx_queue_len = 0;
10663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->flags |= IFF_MULTICAST;
10673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
10683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	/*
10703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * Indicate we support unicast address filtering. That way core won't
10713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * bring us to promisc mode in case a unicast addr is added.
10723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 * Let this up to underlay drivers.
10733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	 */
10743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->priv_flags |= IFF_UNICAST_FLT;
10753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->features |= NETIF_F_LLTX;
10773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->features |= NETIF_F_GRO;
10783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->hw_features = NETIF_F_HW_VLAN_TX |
10793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   NETIF_F_HW_VLAN_RX |
10803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			   NETIF_F_HW_VLAN_FILTER;
10813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	dev->features |= dev->hw_features;
10833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
10843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_newlink(struct net *src_net, struct net_device *dev,
10863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			struct nlattr *tb[], struct nlattr *data[])
10873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
10883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
10893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (tb[IFLA_ADDRESS] == NULL)
10917ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka		eth_hw_addr_random(dev);
10923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = register_netdevice(dev);
10943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
10953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return err;
10963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
10973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
10983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
10993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_validate(struct nlattr *tb[], struct nlattr *data[])
11013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
11023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (tb[IFLA_ADDRESS]) {
11033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
11043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return -EINVAL;
11053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
11063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			return -EADDRNOTAVAIL;
11073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
11083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
11093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
11103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct rtnl_link_ops team_link_ops __read_mostly = {
11123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.kind		= DRV_NAME,
11133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.priv_size	= sizeof(struct team),
11143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.setup		= team_setup,
11153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.newlink	= team_newlink,
11163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.validate	= team_validate,
11173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
11183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/***********************************
11213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Generic netlink custom interface
11223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ***********************************/
11233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct genl_family team_nl_family = {
11253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.id		= GENL_ID_GENERATE,
11263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.name		= TEAM_GENL_NAME,
11273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.version	= TEAM_GENL_VERSION,
11283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.maxattr	= TEAM_ATTR_MAX,
11293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.netnsok	= true,
11303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
11313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
11333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_UNSPEC]			= { .type = NLA_UNSPEC, },
11343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_TEAM_IFINDEX]		= { .type = NLA_U32 },
11353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_LIST_OPTION]			= { .type = NLA_NESTED },
11363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_LIST_PORT]			= { .type = NLA_NESTED },
11373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
11383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic const struct nla_policy
11403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoteam_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
11413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_OPTION_UNSPEC]		= { .type = NLA_UNSPEC, },
11423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_OPTION_NAME] = {
11433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.type = NLA_STRING,
11443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.len = TEAM_STRING_MAX_LEN,
11453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
11463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_OPTION_CHANGED]		= { .type = NLA_FLAG },
11473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_OPTION_TYPE]			= { .type = NLA_U8 },
11483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	[TEAM_ATTR_OPTION_DATA] = {
11493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.type = NLA_BINARY,
11503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.len = TEAM_STRING_MAX_LEN,
11513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
11523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
11533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
11553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
11563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sk_buff *msg;
11573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	void *hdr;
11583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
11593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
11613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!msg)
11623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
11633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
11653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			  &team_nl_family, 0, TEAM_CMD_NOOP);
11663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (IS_ERR(hdr)) {
11673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = PTR_ERR(hdr);
11683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_msg_put;
11693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
11703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	genlmsg_end(msg, hdr);
11723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
11743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_msg_put:
11763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nlmsg_free(msg);
11773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
11793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
11803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/*
11823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Netlink cmd functions should be locked by following two functions.
11838c0713a57482ebfadef197c856a38af3a55444c6Jiri Pirko * Since dev gets held here, that ensures dev won't disappear in between.
11843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko */
11853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct team *team_nl_team_get(struct genl_info *info)
11863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
11873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net *net = genl_info_net(info);
11883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int ifindex;
11893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net_device *dev;
11903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team;
11913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
11933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return NULL;
11943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
11953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
11968c0713a57482ebfadef197c856a38af3a55444c6Jiri Pirko	dev = dev_get_by_index(net, ifindex);
11973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!dev || dev->netdev_ops != &team_netdev_ops) {
11988c0713a57482ebfadef197c856a38af3a55444c6Jiri Pirko		if (dev)
11998c0713a57482ebfadef197c856a38af3a55444c6Jiri Pirko			dev_put(dev);
12003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return NULL;
12013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
12023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team = netdev_priv(dev);
120461dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
12053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return team;
12063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
12073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_nl_team_put(struct team *team)
12093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
121061dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
12118c0713a57482ebfadef197c856a38af3a55444c6Jiri Pirko	dev_put(team->dev);
12123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
12133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_send_generic(struct genl_info *info, struct team *team,
12153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				int (*fill_func)(struct sk_buff *skb,
12163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko						 struct genl_info *info,
12173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko						 int flags, struct team *team))
12183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
12193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sk_buff *skb;
12203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
12213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
12233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!skb)
12243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
12253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = fill_func(skb, info, NLM_F_ACK, team);
12273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err < 0)
12283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_fill;
12293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
12313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
12323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_fill:
12343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nlmsg_free(skb);
12353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
12363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
12373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1238b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_fill_options_get(struct sk_buff *skb,
1239b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko				    u32 pid, u32 seq, int flags,
1240b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko				    struct team *team, bool fillall)
12413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
12423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct nlattr *option_list;
12433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	void *hdr;
12443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_option *option;
12453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
12473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			  TEAM_CMD_OPTIONS_GET);
12483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (IS_ERR(hdr))
12493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return PTR_ERR(hdr);
12503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
12523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
12533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!option_list)
12543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EMSGSIZE;
12553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(option, &team->option_list, list) {
12573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct nlattr *option_item;
12583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		long arg;
12593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1260b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		/* Include only changed options if fill all mode is not on */
1261b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (!fillall && !option->changed)
1262b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			continue;
12633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
12643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!option_item)
12653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto nla_put_failure;
12663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name);
1267b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (option->changed) {
12683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED);
1269b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			option->changed = false;
1270b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		}
1271b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (option->removed)
1272b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_REMOVED);
12733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		switch (option->type) {
12743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		case TEAM_OPTION_TYPE_U32:
12753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32);
12763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			team_option_get(team, option, &arg);
12773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg);
12783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			break;
12793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		case TEAM_OPTION_TYPE_STRING:
12803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING);
12813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			team_option_get(team, option, &arg);
12823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA,
12833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				       (char *) arg);
12843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			break;
12853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		default:
12863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			BUG();
12873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
12883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		nla_nest_end(skb, option_item);
12893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
12903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nla_nest_end(skb, option_list);
12923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return genlmsg_end(skb, hdr);
12933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
12943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkonla_put_failure:
12953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	genlmsg_cancel(skb, hdr);
12963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return -EMSGSIZE;
12973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
12983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1299b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_fill_options_get_all(struct sk_buff *skb,
1300b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					struct genl_info *info, int flags,
1301b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					struct team *team)
13023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
1303b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	return team_nl_fill_options_get(skb, info->snd_pid,
1304b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					info->snd_seq, NLM_F_ACK,
1305b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					team, true);
13063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
13073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
13093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
13103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team;
13113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
13123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team = team_nl_team_get(info);
13143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!team)
13153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
13163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1317b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_send_generic(info, team, team_nl_fill_options_get_all);
13183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_nl_team_put(team);
13203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
13223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
13233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
13253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
13263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team;
13273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err = 0;
13283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int i;
13293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct nlattr *nl_option;
13303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team = team_nl_team_get(info);
13323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!team)
13333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
13343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = -EINVAL;
13363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!info->attrs[TEAM_ATTR_LIST_OPTION]) {
13373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = -EINVAL;
13383d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto team_put;
13393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
13403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
13423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
13433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		enum team_option_type opt_type;
13443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct team_option *option;
13453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		char *opt_name;
13463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		bool opt_found = false;
13473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (nla_type(nl_option) != TEAM_ATTR_ITEM_OPTION) {
13493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			err = -EINVAL;
13503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto team_put;
13513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
13523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
13533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				       nl_option, team_nl_option_policy);
13543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (err)
13553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto team_put;
13563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
13573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		    !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
13583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		    !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
13593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			err = -EINVAL;
13603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto team_put;
13613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
13623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
13633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		case NLA_U32:
13643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			opt_type = TEAM_OPTION_TYPE_U32;
13653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			break;
13663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		case NLA_STRING:
13673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			opt_type = TEAM_OPTION_TYPE_STRING;
13683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			break;
13693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		default:
13703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto team_put;
13713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
13723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
13743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		list_for_each_entry(option, &team->option_list, list) {
13753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			long arg;
13763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			struct nlattr *opt_data_attr;
13773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
13783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			if (option->type != opt_type ||
13793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			    strcmp(option->name, opt_name))
13803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				continue;
13813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			opt_found = true;
13823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
13833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			switch (opt_type) {
13843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			case TEAM_OPTION_TYPE_U32:
13853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				arg = nla_get_u32(opt_data_attr);
13863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				break;
13873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			case TEAM_OPTION_TYPE_STRING:
13883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				arg = (long) nla_data(opt_data_attr);
13893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				break;
13903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			default:
13913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				BUG();
13923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			}
13933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			err = team_option_set(team, option, &arg);
13943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			if (err)
13953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				goto team_put;
13963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
13973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!opt_found) {
13983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			err = -ENOENT;
13993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto team_put;
14003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
14013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
14023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoteam_put:
14043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_nl_team_put(team);
14053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
14073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
14083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1409b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_fill_port_list_get(struct sk_buff *skb,
1410b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko				      u32 pid, u32 seq, int flags,
1411b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko				      struct team *team,
1412b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko				      bool fillall)
14133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
14143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct nlattr *port_list;
14153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	void *hdr;
14163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
14173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
14193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			  TEAM_CMD_PORT_LIST_GET);
14203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (IS_ERR(hdr))
14213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return PTR_ERR(hdr);
14223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
14243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
14253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!port_list)
14263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EMSGSIZE;
14273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	list_for_each_entry(port, &team->port_list, list) {
14293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct nlattr *port_item;
14303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1431b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		/* Include only changed ports if fill all mode is not on */
1432b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (!fillall && !port->changed)
1433b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			continue;
14343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
14353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!port_item)
14363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto nla_put_failure;
14373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex);
1438b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (port->changed) {
14393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED);
1440b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			port->changed = false;
1441b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		}
1442b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko		if (port->removed)
1443b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko			NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_REMOVED);
14443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (port->linkup)
14453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP);
14463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed);
14473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex);
14483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		nla_nest_end(skb, port_item);
14493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
14503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nla_nest_end(skb, port_list);
14523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return genlmsg_end(skb, hdr);
14533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkonla_put_failure:
14553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	genlmsg_cancel(skb, hdr);
14563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return -EMSGSIZE;
14573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
14583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1459b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_fill_port_list_get_all(struct sk_buff *skb,
1460b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					  struct genl_info *info, int flags,
1461b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					  struct team *team)
14623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
1463b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	return team_nl_fill_port_list_get(skb, info->snd_pid,
1464b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					  info->snd_seq, NLM_F_ACK,
1465b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko					  team, true);
14663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
14673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_cmd_port_list_get(struct sk_buff *skb,
14693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				     struct genl_info *info)
14703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
14713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team;
14723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
14733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team = team_nl_team_get(info);
14753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!team)
14763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -EINVAL;
14773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1478b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_send_generic(info, team, team_nl_fill_port_list_get_all);
14793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_nl_team_put(team);
14813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
14833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
14843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
14853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct genl_ops team_nl_ops[] = {
14863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	{
14873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.cmd = TEAM_CMD_NOOP,
14883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.doit = team_nl_cmd_noop,
14893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.policy = team_nl_policy,
14903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
14913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	{
14923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.cmd = TEAM_CMD_OPTIONS_SET,
14933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.doit = team_nl_cmd_options_set,
14943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.policy = team_nl_policy,
14953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.flags = GENL_ADMIN_PERM,
14963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
14973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	{
14983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.cmd = TEAM_CMD_OPTIONS_GET,
14993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.doit = team_nl_cmd_options_get,
15003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.policy = team_nl_policy,
15013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.flags = GENL_ADMIN_PERM,
15023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
15033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	{
15043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.cmd = TEAM_CMD_PORT_LIST_GET,
15053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.doit = team_nl_cmd_port_list_get,
15063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.policy = team_nl_policy,
15073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		.flags = GENL_ADMIN_PERM,
15083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	},
15093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
15103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct genl_multicast_group team_change_event_mcgrp = {
15123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
15133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
15143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1515b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_send_event_options_get(struct team *team)
15163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
15173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sk_buff *skb;
15183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
15193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net *net = dev_net(team->dev);
15203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
15223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!skb)
15233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
15243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1525b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_fill_options_get(skb, 0, 0, 0, team, false);
15263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err < 0)
15273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_fill;
15283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
15303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				      GFP_KERNEL);
15313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
15323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_fill:
15343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nlmsg_free(skb);
15353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
15363d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
15373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1538b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic int team_nl_send_event_port_list_get(struct team *team)
15393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
15403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct sk_buff *skb;
15413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
1542b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	struct net *net = dev_net(team->dev);
15433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
15453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!skb)
15463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return -ENOMEM;
15473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1548b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_fill_port_list_get(skb, 0, 0, 0, team, false);
15493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err < 0)
15503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_fill;
15513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
15533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko				      GFP_KERNEL);
15543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
15553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_fill:
15573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	nlmsg_free(skb);
15583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
15593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
15603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_nl_init(void)
15623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
15633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
15643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
15663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko					    ARRAY_SIZE(team_nl_ops));
15673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
15683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return err;
15693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
15713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
15723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_change_event_grp_reg;
15733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
15753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_change_event_grp_reg:
15773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	genl_unregister_family(&team_nl_family);
15783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
15803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
15813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_nl_fini(void)
15833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
15843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	genl_unregister_family(&team_nl_family);
15853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
15863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
15883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/******************
15893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Change checkers
15903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ******************/
15913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1592b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirkostatic void __team_options_change_check(struct team *team)
15933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
15943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
15953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1596b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_send_event_options_get(team);
15973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
15983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_warn(team->dev, "Failed to send options change via netlink\n");
15993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
16003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/* rtnl lock is held */
16023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __team_port_change_check(struct team_port *port, bool linkup)
16033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
16043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
16053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1606b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	if (!port->removed && port->linkup == linkup)
16073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return;
16083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
1609b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	port->changed = true;
16103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->linkup = linkup;
16113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (linkup) {
16123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		struct ethtool_cmd ecmd;
16133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		err = __ethtool_get_settings(port->dev, &ecmd);
16153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (!err) {
16163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			port->speed = ethtool_cmd_speed(&ecmd);
16173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			port->duplex = ecmd.duplex;
16183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			goto send_event;
16193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		}
16203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
16213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->speed = 0;
16223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port->duplex = 0;
16233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkosend_event:
1625b82b9183d4f18f9b8c4bb31f223eb6c79b734eb0Jiri Pirko	err = team_nl_send_event_port_list_get(port->team);
16263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
16273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n",
16283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			    port->dev->name);
16293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16303d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
16313d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16323d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void team_port_change_check(struct team_port *port, bool linkup)
16333d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
16343d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team *team = port->team;
16353d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
163661dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_lock(&team->lock);
16373d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	__team_port_change_check(port, linkup);
163861dc3461b9549bc10a2f16d254250680cadafcceJiri Pirko	mutex_unlock(&team->lock);
16393d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
16403d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16413d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/************************************
16423d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Net device notifier event handler
16433d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ************************************/
16443d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16453d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int team_device_event(struct notifier_block *unused,
16463d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			     unsigned long event, void *ptr)
16473d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
16483d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct net_device *dev = (struct net_device *) ptr;
16493d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	struct team_port *port;
16503d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16513d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	port = team_port_get_rtnl(dev);
16523d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (!port)
16533d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return NOTIFY_DONE;
16543d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16553d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	switch (event) {
16563d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_UP:
16573d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (netif_carrier_ok(dev))
16583d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			team_port_change_check(port, true);
16593d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_DOWN:
16603d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_port_change_check(port, false);
16613d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_CHANGE:
16623d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		if (netif_running(port->dev))
16633d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko			team_port_change_check(port,
16643d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko					       !!netif_carrier_ok(port->dev));
16653d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		break;
16663d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_UNREGISTER:
16673d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_del_slave(port->team->dev, dev);
16683d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		break;
16693d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_FEAT_CHANGE:
16703d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		team_compute_features(port->team);
16713d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		break;
16723d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_CHANGEMTU:
16733d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		/* Forbid to change mtu of underlaying device */
16743d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return NOTIFY_BAD;
16753d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	case NETDEV_PRE_TYPE_CHANGE:
16763d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		/* Forbid to change type of underlaying device */
16773d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		return NOTIFY_BAD;
16783d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	}
16793d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return NOTIFY_DONE;
16803d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
16813d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16823d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic struct notifier_block team_notifier_block __read_mostly = {
16833d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	.notifier_call = team_device_event,
16843d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko};
16853d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16863d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16873d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko/***********************
16883d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko * Module init and exit
16893d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko ***********************/
16903d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16913d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic int __init team_module_init(void)
16923d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
16933d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	int err;
16943d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16953d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	register_netdevice_notifier(&team_notifier_block);
16963d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
16973d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = rtnl_link_register(&team_link_ops);
16983d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
16993d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_rtnl_reg;
17003d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17013d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	err = team_nl_init();
17023d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	if (err)
17033d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko		goto err_nl_init;
17043d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17053d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return 0;
17063d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17073d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_nl_init:
17083d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rtnl_link_unregister(&team_link_ops);
17093d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17103d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkoerr_rtnl_reg:
17113d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	unregister_netdevice_notifier(&team_notifier_block);
17123d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17133d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	return err;
17143d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
17153d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17163d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkostatic void __exit team_module_exit(void)
17173d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko{
17183d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	team_nl_fini();
17193d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	rtnl_link_unregister(&team_link_ops);
17203d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko	unregister_netdevice_notifier(&team_notifier_block);
17213d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko}
17223d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17233d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkomodule_init(team_module_init);
17243d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirkomodule_exit(team_module_exit);
17253d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri Pirko
17263d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoMODULE_LICENSE("GPL v2");
17273d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoMODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
17283d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoMODULE_DESCRIPTION("Ethernet team device driver");
17293d249d4ca7d0ed6629a135ea1ea21c72286c0d80Jiri PirkoMODULE_ALIAS_RTNL_LINK(DRV_NAME);
1730