if_team.h 6.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 * 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__

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;
	struct hlist_node hlist; /* node in hash list */
	struct list_head list; /* node in ordinary list */
	struct team *team;
	int index;

	/*
	 * 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;

	bool linkup;
	u32 speed;
	u8 duplex;

49 50 51 52
	/* Custom gennetlink interface related flags */
	bool changed;
	bool removed;

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	struct rcu_head rcu;
};

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);
};

enum team_option_type {
	TEAM_OPTION_TYPE_U32,
	TEAM_OPTION_TYPE_STRING,
J
Jiri Pirko 已提交
71
	TEAM_OPTION_TYPE_BINARY,
J
Jiri Pirko 已提交
72
	TEAM_OPTION_TYPE_BOOL,
73 74
};

75 76 77 78 79 80 81 82
struct team_gsetter_ctx {
	union {
		u32 u32_val;
		const char *str_val;
		struct {
			const void *ptr;
			u32 len;
		} bin_val;
J
Jiri Pirko 已提交
83
		bool bool_val;
84 85 86 87
	} data;
	struct team_port *port;
};

88 89 90
struct team_option {
	struct list_head list;
	const char *name;
91
	bool per_port;
92
	enum team_option_type type;
93 94
	int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
	int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
};

struct team_mode {
	struct list_head list;
	const char *kind;
	struct module *owner;
	size_t priv_size;
	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;

115
	struct mutex lock; /* used for overall locking, e.g. port lists write */
116 117 118 119 120 121 122 123 124

	/*
	 * port lists with port count
	 */
	int port_count;
	struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES];
	struct list_head port_list;

	struct list_head option_list;
125
	struct list_head option_inst_list; /* list of option instances */
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

	const struct team_mode *mode;
	struct team_mode_ops ops;
	long mode_priv[TEAM_MODE_PRIV_LONGS];
};

static inline struct hlist_head *team_port_index_hash(struct team *team,
						      int port_index)
{
	return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
}

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 已提交
164 165 166
extern int team_options_register(struct team *team,
				 const struct team_option *option,
				 size_t option_count);
167
extern void team_options_unregister(struct team *team,
J
Jiri Pirko 已提交
168
				    const struct team_option *option,
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
				    size_t option_count);
extern int team_mode_register(struct team_mode *mode);
extern int team_mode_unregister(struct team_mode *mode);

#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 */
231
	TEAM_ATTR_OPTION_REMOVED,	/* flag */
232
	TEAM_ATTR_OPTION_PORT_IFINDEX,	/* u32 */ /* for per-port options */
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

	__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 */
253
	TEAM_ATTR_PORT_REMOVED,		/* flag */
254 255 256 257 258 259 260 261 262 263 264 265 266

	__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_ */