1/*
2 * include/linux/if_team.h - Network team device driver header
3 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#ifndef _LINUX_IF_TEAM_H_
12#define _LINUX_IF_TEAM_H_
13
14#ifdef __KERNEL__
15
16struct team_pcpu_stats {
17	u64			rx_packets;
18	u64			rx_bytes;
19	u64			rx_multicast;
20	u64			tx_packets;
21	u64			tx_bytes;
22	struct u64_stats_sync	syncp;
23	u32			rx_dropped;
24	u32			tx_dropped;
25};
26
27struct team;
28
29struct team_port {
30	struct net_device *dev;
31	struct hlist_node hlist; /* node in hash list */
32	struct list_head list; /* node in ordinary list */
33	struct team *team;
34	int index;
35
36	/*
37	 * A place for storing original values of the device before it
38	 * become a port.
39	 */
40	struct {
41		unsigned char dev_addr[MAX_ADDR_LEN];
42		unsigned int mtu;
43	} orig;
44
45	bool linkup;
46	u32 speed;
47	u8 duplex;
48
49	/* Custom gennetlink interface related flags */
50	bool changed;
51	bool removed;
52
53	struct rcu_head rcu;
54};
55
56struct team_mode_ops {
57	int (*init)(struct team *team);
58	void (*exit)(struct team *team);
59	rx_handler_result_t (*receive)(struct team *team,
60				       struct team_port *port,
61				       struct sk_buff *skb);
62	bool (*transmit)(struct team *team, struct sk_buff *skb);
63	int (*port_enter)(struct team *team, struct team_port *port);
64	void (*port_leave)(struct team *team, struct team_port *port);
65	void (*port_change_mac)(struct team *team, struct team_port *port);
66};
67
68enum team_option_type {
69	TEAM_OPTION_TYPE_U32,
70	TEAM_OPTION_TYPE_STRING,
71};
72
73struct team_option {
74	struct list_head list;
75	const char *name;
76	enum team_option_type type;
77	int (*getter)(struct team *team, void *arg);
78	int (*setter)(struct team *team, void *arg);
79
80	/* Custom gennetlink interface related flags */
81	bool changed;
82	bool removed;
83};
84
85struct team_mode {
86	struct list_head list;
87	const char *kind;
88	struct module *owner;
89	size_t priv_size;
90	const struct team_mode_ops *ops;
91};
92
93#define TEAM_PORT_HASHBITS 4
94#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
95
96#define TEAM_MODE_PRIV_LONGS 4
97#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
98
99struct team {
100	struct net_device *dev; /* associated netdevice */
101	struct team_pcpu_stats __percpu *pcpu_stats;
102
103	struct mutex lock; /* used for overall locking, e.g. port lists write */
104
105	/*
106	 * port lists with port count
107	 */
108	int port_count;
109	struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES];
110	struct list_head port_list;
111
112	struct list_head option_list;
113
114	const struct team_mode *mode;
115	struct team_mode_ops ops;
116	long mode_priv[TEAM_MODE_PRIV_LONGS];
117};
118
119static inline struct hlist_head *team_port_index_hash(struct team *team,
120						      int port_index)
121{
122	return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
123}
124
125static inline struct team_port *team_get_port_by_index(struct team *team,
126						       int port_index)
127{
128	struct hlist_node *p;
129	struct team_port *port;
130	struct hlist_head *head = team_port_index_hash(team, port_index);
131
132	hlist_for_each_entry(port, p, head, hlist)
133		if (port->index == port_index)
134			return port;
135	return NULL;
136}
137static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
138							   int port_index)
139{
140	struct hlist_node *p;
141	struct team_port *port;
142	struct hlist_head *head = team_port_index_hash(team, port_index);
143
144	hlist_for_each_entry_rcu(port, p, head, hlist)
145		if (port->index == port_index)
146			return port;
147	return NULL;
148}
149
150extern int team_port_set_team_mac(struct team_port *port);
151extern int team_options_register(struct team *team,
152				 const struct team_option *option,
153				 size_t option_count);
154extern void team_options_unregister(struct team *team,
155				    const struct team_option *option,
156				    size_t option_count);
157extern int team_mode_register(struct team_mode *mode);
158extern int team_mode_unregister(struct team_mode *mode);
159
160#endif /* __KERNEL__ */
161
162#define TEAM_STRING_MAX_LEN 32
163
164/**********************************
165 * NETLINK_GENERIC netlink family.
166 **********************************/
167
168enum {
169	TEAM_CMD_NOOP,
170	TEAM_CMD_OPTIONS_SET,
171	TEAM_CMD_OPTIONS_GET,
172	TEAM_CMD_PORT_LIST_GET,
173
174	__TEAM_CMD_MAX,
175	TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
176};
177
178enum {
179	TEAM_ATTR_UNSPEC,
180	TEAM_ATTR_TEAM_IFINDEX,		/* u32 */
181	TEAM_ATTR_LIST_OPTION,		/* nest */
182	TEAM_ATTR_LIST_PORT,		/* nest */
183
184	__TEAM_ATTR_MAX,
185	TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
186};
187
188/* Nested layout of get/set msg:
189 *
190 *	[TEAM_ATTR_LIST_OPTION]
191 *		[TEAM_ATTR_ITEM_OPTION]
192 *			[TEAM_ATTR_OPTION_*], ...
193 *		[TEAM_ATTR_ITEM_OPTION]
194 *			[TEAM_ATTR_OPTION_*], ...
195 *		...
196 *	[TEAM_ATTR_LIST_PORT]
197 *		[TEAM_ATTR_ITEM_PORT]
198 *			[TEAM_ATTR_PORT_*], ...
199 *		[TEAM_ATTR_ITEM_PORT]
200 *			[TEAM_ATTR_PORT_*], ...
201 *		...
202 */
203
204enum {
205	TEAM_ATTR_ITEM_OPTION_UNSPEC,
206	TEAM_ATTR_ITEM_OPTION,		/* nest */
207
208	__TEAM_ATTR_ITEM_OPTION_MAX,
209	TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
210};
211
212enum {
213	TEAM_ATTR_OPTION_UNSPEC,
214	TEAM_ATTR_OPTION_NAME,		/* string */
215	TEAM_ATTR_OPTION_CHANGED,	/* flag */
216	TEAM_ATTR_OPTION_TYPE,		/* u8 */
217	TEAM_ATTR_OPTION_DATA,		/* dynamic */
218	TEAM_ATTR_OPTION_REMOVED,	/* flag */
219
220	__TEAM_ATTR_OPTION_MAX,
221	TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
222};
223
224enum {
225	TEAM_ATTR_ITEM_PORT_UNSPEC,
226	TEAM_ATTR_ITEM_PORT,		/* nest */
227
228	__TEAM_ATTR_ITEM_PORT_MAX,
229	TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
230};
231
232enum {
233	TEAM_ATTR_PORT_UNSPEC,
234	TEAM_ATTR_PORT_IFINDEX,		/* u32 */
235	TEAM_ATTR_PORT_CHANGED,		/* flag */
236	TEAM_ATTR_PORT_LINKUP,		/* flag */
237	TEAM_ATTR_PORT_SPEED,		/* u32 */
238	TEAM_ATTR_PORT_DUPLEX,		/* u8 */
239	TEAM_ATTR_PORT_REMOVED,		/* flag */
240
241	__TEAM_ATTR_PORT_MAX,
242	TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
243};
244
245/*
246 * NETLINK_GENERIC related info
247 */
248#define TEAM_GENL_NAME "team"
249#define TEAM_GENL_VERSION 0x1
250#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"
251
252#endif /* _LINUX_IF_TEAM_H_ */
253