if_team.h 8.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * include/linux/if_team.h - Network team device driver header
 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#ifndef _LINUX_IF_TEAM_H_
#define _LINUX_IF_TEAM_H_

#ifdef __KERNEL__

J
Jiri Pirko 已提交
16
#include <linux/netpoll.h>
J
Jiri Pirko 已提交
17
#include <net/sch_generic.h>
J
Jiri Pirko 已提交
18

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
struct team_pcpu_stats {
	u64			rx_packets;
	u64			rx_bytes;
	u64			rx_multicast;
	u64			tx_packets;
	u64			tx_bytes;
	struct u64_stats_sync	syncp;
	u32			rx_dropped;
	u32			tx_dropped;
};

struct team;

struct team_port {
	struct net_device *dev;
J
Jiri Pirko 已提交
34
	struct hlist_node hlist; /* node in enabled ports hash list */
35 36
	struct list_head list; /* node in ordinary list */
	struct team *team;
J
Jiri Pirko 已提交
37
	int index; /* index of enabled port. If disabled, it's set to -1 */
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
	bool linkup; /* either state.linkup or user.linkup */

	struct {
		bool linkup;
		u32 speed;
		u8 duplex;
	} state;

	/* Values set by userspace */
	struct {
		bool linkup;
		bool linkup_enabled;
	} user;

	/* Custom gennetlink interface related flags */
	bool changed;
	bool removed;

57 58 59 60 61 62 63 64 65
	/*
	 * A place for storing original values of the device before it
	 * become a port.
	 */
	struct {
		unsigned char dev_addr[MAX_ADDR_LEN];
		unsigned int mtu;
	} orig;

J
Jiri Pirko 已提交
66 67 68 69
#ifdef CONFIG_NET_POLL_CONTROLLER
	struct netpoll *np;
#endif

J
Jiri Pirko 已提交
70
	s32 priority; /* lower number ~ higher priority */
71 72
	u16 queue_id;
	struct list_head qom_list; /* node in queue override mapping list */
J
Jiri Pirko 已提交
73
	long mode_priv[0];
74 75
};

76 77 78 79 80 81 82 83 84
static inline bool team_port_enabled(struct team_port *port)
{
	return port->index != -1;
}

static inline bool team_port_txable(struct team_port *port)
{
	return port->linkup && team_port_enabled(port);
}
85

J
Jiri Pirko 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#ifdef CONFIG_NET_POLL_CONTROLLER
static inline void team_netpoll_send_skb(struct team_port *port,
					 struct sk_buff *skb)
{
	struct netpoll *np = port->np;

	if (np)
		netpoll_send_skb(np, skb);
}
#else
static inline void team_netpoll_send_skb(struct team_port *port,
					 struct sk_buff *skb)
{
}
#endif

static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
				      struct sk_buff *skb)
{
J
Jiri Pirko 已提交
105 106 107 108
	BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
		     sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
	skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);

J
Jiri Pirko 已提交
109 110 111 112 113 114 115 116
	skb->dev = port->dev;
	if (unlikely(netpoll_tx_running(port->dev))) {
		team_netpoll_send_skb(port, skb);
		return 0;
	}
	return dev_queue_xmit(skb);
}

117 118 119 120 121 122 123 124 125 126
struct team_mode_ops {
	int (*init)(struct team *team);
	void (*exit)(struct team *team);
	rx_handler_result_t (*receive)(struct team *team,
				       struct team_port *port,
				       struct sk_buff *skb);
	bool (*transmit)(struct team *team, struct sk_buff *skb);
	int (*port_enter)(struct team *team, struct team_port *port);
	void (*port_leave)(struct team *team, struct team_port *port);
	void (*port_change_mac)(struct team *team, struct team_port *port);
127 128
	void (*port_enabled)(struct team *team, struct team_port *port);
	void (*port_disabled)(struct team *team, struct team_port *port);
129 130 131 132 133
};

enum team_option_type {
	TEAM_OPTION_TYPE_U32,
	TEAM_OPTION_TYPE_STRING,
J
Jiri Pirko 已提交
134
	TEAM_OPTION_TYPE_BINARY,
J
Jiri Pirko 已提交
135
	TEAM_OPTION_TYPE_BOOL,
136
	TEAM_OPTION_TYPE_S32,
137 138
};

139 140 141 142 143
struct team_option_inst_info {
	u32 array_index;
	struct team_port *port; /* != NULL if per-port */
};

144 145 146 147 148 149 150 151
struct team_gsetter_ctx {
	union {
		u32 u32_val;
		const char *str_val;
		struct {
			const void *ptr;
			u32 len;
		} bin_val;
J
Jiri Pirko 已提交
152
		bool bool_val;
153
		s32 s32_val;
154
	} data;
155
	struct team_option_inst_info *info;
156 157
};

158 159 160
struct team_option {
	struct list_head list;
	const char *name;
161
	bool per_port;
J
Jiri Pirko 已提交
162
	unsigned int array_size; /* != 0 means the option is array */
163
	enum team_option_type type;
164
	int (*init)(struct team *team, struct team_option_inst_info *info);
165 166
	int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
	int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
167 168
};

J
Jiri Pirko 已提交
169 170 171
extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info);
extern void team_options_change_check(struct team *team);

172 173 174 175
struct team_mode {
	const char *kind;
	struct module *owner;
	size_t priv_size;
J
Jiri Pirko 已提交
176
	size_t port_priv_size;
177 178 179 180 181 182 183 184 185 186 187 188 189
	const struct team_mode_ops *ops;
};

#define TEAM_PORT_HASHBITS 4
#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)

#define TEAM_MODE_PRIV_LONGS 4
#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)

struct team {
	struct net_device *dev; /* associated netdevice */
	struct team_pcpu_stats __percpu *pcpu_stats;

190
	struct mutex lock; /* used for overall locking, e.g. port lists write */
191 192

	/*
J
Jiri Pirko 已提交
193
	 * List of enabled ports and their count
194
	 */
J
Jiri Pirko 已提交
195 196 197 198
	int en_port_count;
	struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES];

	struct list_head port_list; /* list of all ports */
199 200

	struct list_head option_list;
201
	struct list_head option_inst_list; /* list of option instances */
202 203 204

	const struct team_mode *mode;
	struct team_mode_ops ops;
205 206
	bool queue_override_enabled;
	struct list_head *qom_lists; /* array of queue override mapping lists */
207 208 209 210 211 212
	long mode_priv[TEAM_MODE_PRIV_LONGS];
};

static inline struct hlist_head *team_port_index_hash(struct team *team,
						      int port_index)
{
J
Jiri Pirko 已提交
213
	return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
}

static inline struct team_port *team_get_port_by_index(struct team *team,
						       int port_index)
{
	struct hlist_node *p;
	struct team_port *port;
	struct hlist_head *head = team_port_index_hash(team, port_index);

	hlist_for_each_entry(port, p, head, hlist)
		if (port->index == port_index)
			return port;
	return NULL;
}
static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
							   int port_index)
{
	struct hlist_node *p;
	struct team_port *port;
	struct hlist_head *head = team_port_index_hash(team, port_index);

	hlist_for_each_entry_rcu(port, p, head, hlist)
		if (port->index == port_index)
			return port;
	return NULL;
}

extern int team_port_set_team_mac(struct team_port *port);
J
Jiri Pirko 已提交
242 243 244
extern int team_options_register(struct team *team,
				 const struct team_option *option,
				 size_t option_count);
245
extern void team_options_unregister(struct team *team,
J
Jiri Pirko 已提交
246
				    const struct team_option *option,
247
				    size_t option_count);
J
Jiri Pirko 已提交
248 249
extern int team_mode_register(const struct team_mode *mode);
extern void team_mode_unregister(const struct team_mode *mode);
250

J
Jiri Pirko 已提交
251 252 253
#define TEAM_DEFAULT_NUM_TX_QUEUES 16
#define TEAM_DEFAULT_NUM_RX_QUEUES 16

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
#endif /* __KERNEL__ */

#define TEAM_STRING_MAX_LEN 32

/**********************************
 * NETLINK_GENERIC netlink family.
 **********************************/

enum {
	TEAM_CMD_NOOP,
	TEAM_CMD_OPTIONS_SET,
	TEAM_CMD_OPTIONS_GET,
	TEAM_CMD_PORT_LIST_GET,

	__TEAM_CMD_MAX,
	TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
};

enum {
	TEAM_ATTR_UNSPEC,
	TEAM_ATTR_TEAM_IFINDEX,		/* u32 */
	TEAM_ATTR_LIST_OPTION,		/* nest */
	TEAM_ATTR_LIST_PORT,		/* nest */

	__TEAM_ATTR_MAX,
	TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
};

/* Nested layout of get/set msg:
 *
 *	[TEAM_ATTR_LIST_OPTION]
 *		[TEAM_ATTR_ITEM_OPTION]
 *			[TEAM_ATTR_OPTION_*], ...
 *		[TEAM_ATTR_ITEM_OPTION]
 *			[TEAM_ATTR_OPTION_*], ...
 *		...
 *	[TEAM_ATTR_LIST_PORT]
 *		[TEAM_ATTR_ITEM_PORT]
 *			[TEAM_ATTR_PORT_*], ...
 *		[TEAM_ATTR_ITEM_PORT]
 *			[TEAM_ATTR_PORT_*], ...
 *		...
 */

enum {
	TEAM_ATTR_ITEM_OPTION_UNSPEC,
	TEAM_ATTR_ITEM_OPTION,		/* nest */

	__TEAM_ATTR_ITEM_OPTION_MAX,
	TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
};

enum {
	TEAM_ATTR_OPTION_UNSPEC,
	TEAM_ATTR_OPTION_NAME,		/* string */
	TEAM_ATTR_OPTION_CHANGED,	/* flag */
	TEAM_ATTR_OPTION_TYPE,		/* u8 */
	TEAM_ATTR_OPTION_DATA,		/* dynamic */
312
	TEAM_ATTR_OPTION_REMOVED,	/* flag */
313
	TEAM_ATTR_OPTION_PORT_IFINDEX,	/* u32 */ /* for per-port options */
J
Jiri Pirko 已提交
314
	TEAM_ATTR_OPTION_ARRAY_INDEX,	/* u32 */ /* for array options */
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334

	__TEAM_ATTR_OPTION_MAX,
	TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
};

enum {
	TEAM_ATTR_ITEM_PORT_UNSPEC,
	TEAM_ATTR_ITEM_PORT,		/* nest */

	__TEAM_ATTR_ITEM_PORT_MAX,
	TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
};

enum {
	TEAM_ATTR_PORT_UNSPEC,
	TEAM_ATTR_PORT_IFINDEX,		/* u32 */
	TEAM_ATTR_PORT_CHANGED,		/* flag */
	TEAM_ATTR_PORT_LINKUP,		/* flag */
	TEAM_ATTR_PORT_SPEED,		/* u32 */
	TEAM_ATTR_PORT_DUPLEX,		/* u8 */
335
	TEAM_ATTR_PORT_REMOVED,		/* flag */
336 337 338 339 340 341 342 343 344 345 346 347 348

	__TEAM_ATTR_PORT_MAX,
	TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
};

/*
 * NETLINK_GENERIC related info
 */
#define TEAM_GENL_NAME "team"
#define TEAM_GENL_VERSION 0x1
#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"

#endif /* _LINUX_IF_TEAM_H_ */