1 /* 2 * include/linux/if_team.h - Network team device driver header 3 * Copyright (c) 2011 Jiri Pirko <[email protected]> 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 16 #include <linux/netpoll.h> 17 #include <net/sch_generic.h> 18 19 struct team_pcpu_stats { 20 u64 rx_packets; 21 u64 rx_bytes; 22 u64 rx_multicast; 23 u64 tx_packets; 24 u64 tx_bytes; 25 struct u64_stats_sync syncp; 26 u32 rx_dropped; 27 u32 tx_dropped; 28 }; 29 30 struct team; 31 32 struct team_port { 33 struct net_device *dev; 34 struct hlist_node hlist; /* node in enabled ports hash list */ 35 struct list_head list; /* node in ordinary list */ 36 struct team *team; 37 int index; /* index of enabled port. If disabled, it's set to -1 */ 38 39 bool linkup; /* either state.linkup or user.linkup */ 40 41 struct { 42 bool linkup; 43 u32 speed; 44 u8 duplex; 45 } state; 46 47 /* Values set by userspace */ 48 struct { 49 bool linkup; 50 bool linkup_enabled; 51 } user; 52 53 /* Custom gennetlink interface related flags */ 54 bool changed; 55 bool removed; 56 57 /* 58 * A place for storing original values of the device before it 59 * become a port. 60 */ 61 struct { 62 unsigned char dev_addr[MAX_ADDR_LEN]; 63 unsigned int mtu; 64 } orig; 65 66 #ifdef CONFIG_NET_POLL_CONTROLLER 67 struct netpoll *np; 68 #endif 69 70 long mode_priv[0]; 71 }; 72 73 static inline bool team_port_enabled(struct team_port *port) 74 { 75 return port->index != -1; 76 } 77 78 static inline bool team_port_txable(struct team_port *port) 79 { 80 return port->linkup && team_port_enabled(port); 81 } 82 83 #ifdef CONFIG_NET_POLL_CONTROLLER 84 static inline void team_netpoll_send_skb(struct team_port *port, 85 struct sk_buff *skb) 86 { 87 struct netpoll *np = port->np; 88 89 if (np) 90 netpoll_send_skb(np, skb); 91 } 92 #else 93 static inline void team_netpoll_send_skb(struct team_port *port, 94 struct sk_buff *skb) 95 { 96 } 97 #endif 98 99 static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, 100 struct sk_buff *skb) 101 { 102 BUILD_BUG_ON(sizeof(skb->queue_mapping) != 103 sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); 104 skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); 105 106 skb->dev = port->dev; 107 if (unlikely(netpoll_tx_running(port->dev))) { 108 team_netpoll_send_skb(port, skb); 109 return 0; 110 } 111 return dev_queue_xmit(skb); 112 } 113 114 struct team_mode_ops { 115 int (*init)(struct team *team); 116 void (*exit)(struct team *team); 117 rx_handler_result_t (*receive)(struct team *team, 118 struct team_port *port, 119 struct sk_buff *skb); 120 bool (*transmit)(struct team *team, struct sk_buff *skb); 121 int (*port_enter)(struct team *team, struct team_port *port); 122 void (*port_leave)(struct team *team, struct team_port *port); 123 void (*port_change_mac)(struct team *team, struct team_port *port); 124 void (*port_enabled)(struct team *team, struct team_port *port); 125 void (*port_disabled)(struct team *team, struct team_port *port); 126 }; 127 128 enum team_option_type { 129 TEAM_OPTION_TYPE_U32, 130 TEAM_OPTION_TYPE_STRING, 131 TEAM_OPTION_TYPE_BINARY, 132 TEAM_OPTION_TYPE_BOOL, 133 }; 134 135 struct team_option_inst_info { 136 u32 array_index; 137 struct team_port *port; /* != NULL if per-port */ 138 }; 139 140 struct team_gsetter_ctx { 141 union { 142 u32 u32_val; 143 const char *str_val; 144 struct { 145 const void *ptr; 146 u32 len; 147 } bin_val; 148 bool bool_val; 149 } data; 150 struct team_option_inst_info *info; 151 }; 152 153 struct team_option { 154 struct list_head list; 155 const char *name; 156 bool per_port; 157 unsigned int array_size; /* != 0 means the option is array */ 158 enum team_option_type type; 159 int (*init)(struct team *team, struct team_option_inst_info *info); 160 int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); 161 int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); 162 }; 163 164 extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info); 165 extern void team_options_change_check(struct team *team); 166 167 struct team_mode { 168 const char *kind; 169 struct module *owner; 170 size_t priv_size; 171 size_t port_priv_size; 172 const struct team_mode_ops *ops; 173 }; 174 175 #define TEAM_PORT_HASHBITS 4 176 #define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS) 177 178 #define TEAM_MODE_PRIV_LONGS 4 179 #define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS) 180 181 struct team { 182 struct net_device *dev; /* associated netdevice */ 183 struct team_pcpu_stats __percpu *pcpu_stats; 184 185 struct mutex lock; /* used for overall locking, e.g. port lists write */ 186 187 /* 188 * List of enabled ports and their count 189 */ 190 int en_port_count; 191 struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES]; 192 193 struct list_head port_list; /* list of all ports */ 194 195 struct list_head option_list; 196 struct list_head option_inst_list; /* list of option instances */ 197 198 const struct team_mode *mode; 199 struct team_mode_ops ops; 200 long mode_priv[TEAM_MODE_PRIV_LONGS]; 201 }; 202 203 static inline struct hlist_head *team_port_index_hash(struct team *team, 204 int port_index) 205 { 206 return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 207 } 208 209 static inline struct team_port *team_get_port_by_index(struct team *team, 210 int port_index) 211 { 212 struct hlist_node *p; 213 struct team_port *port; 214 struct hlist_head *head = team_port_index_hash(team, port_index); 215 216 hlist_for_each_entry(port, p, head, hlist) 217 if (port->index == port_index) 218 return port; 219 return NULL; 220 } 221 static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 222 int port_index) 223 { 224 struct hlist_node *p; 225 struct team_port *port; 226 struct hlist_head *head = team_port_index_hash(team, port_index); 227 228 hlist_for_each_entry_rcu(port, p, head, hlist) 229 if (port->index == port_index) 230 return port; 231 return NULL; 232 } 233 234 extern int team_port_set_team_mac(struct team_port *port); 235 extern int team_options_register(struct team *team, 236 const struct team_option *option, 237 size_t option_count); 238 extern void team_options_unregister(struct team *team, 239 const struct team_option *option, 240 size_t option_count); 241 extern int team_mode_register(const struct team_mode *mode); 242 extern void team_mode_unregister(const struct team_mode *mode); 243 244 #define TEAM_DEFAULT_NUM_TX_QUEUES 16 245 #define TEAM_DEFAULT_NUM_RX_QUEUES 16 246 247 #endif /* __KERNEL__ */ 248 249 #define TEAM_STRING_MAX_LEN 32 250 251 /********************************** 252 * NETLINK_GENERIC netlink family. 253 **********************************/ 254 255 enum { 256 TEAM_CMD_NOOP, 257 TEAM_CMD_OPTIONS_SET, 258 TEAM_CMD_OPTIONS_GET, 259 TEAM_CMD_PORT_LIST_GET, 260 261 __TEAM_CMD_MAX, 262 TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1), 263 }; 264 265 enum { 266 TEAM_ATTR_UNSPEC, 267 TEAM_ATTR_TEAM_IFINDEX, /* u32 */ 268 TEAM_ATTR_LIST_OPTION, /* nest */ 269 TEAM_ATTR_LIST_PORT, /* nest */ 270 271 __TEAM_ATTR_MAX, 272 TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1, 273 }; 274 275 /* Nested layout of get/set msg: 276 * 277 * [TEAM_ATTR_LIST_OPTION] 278 * [TEAM_ATTR_ITEM_OPTION] 279 * [TEAM_ATTR_OPTION_*], ... 280 * [TEAM_ATTR_ITEM_OPTION] 281 * [TEAM_ATTR_OPTION_*], ... 282 * ... 283 * [TEAM_ATTR_LIST_PORT] 284 * [TEAM_ATTR_ITEM_PORT] 285 * [TEAM_ATTR_PORT_*], ... 286 * [TEAM_ATTR_ITEM_PORT] 287 * [TEAM_ATTR_PORT_*], ... 288 * ... 289 */ 290 291 enum { 292 TEAM_ATTR_ITEM_OPTION_UNSPEC, 293 TEAM_ATTR_ITEM_OPTION, /* nest */ 294 295 __TEAM_ATTR_ITEM_OPTION_MAX, 296 TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1, 297 }; 298 299 enum { 300 TEAM_ATTR_OPTION_UNSPEC, 301 TEAM_ATTR_OPTION_NAME, /* string */ 302 TEAM_ATTR_OPTION_CHANGED, /* flag */ 303 TEAM_ATTR_OPTION_TYPE, /* u8 */ 304 TEAM_ATTR_OPTION_DATA, /* dynamic */ 305 TEAM_ATTR_OPTION_REMOVED, /* flag */ 306 TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */ 307 TEAM_ATTR_OPTION_ARRAY_INDEX, /* u32 */ /* for array options */ 308 309 __TEAM_ATTR_OPTION_MAX, 310 TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1, 311 }; 312 313 enum { 314 TEAM_ATTR_ITEM_PORT_UNSPEC, 315 TEAM_ATTR_ITEM_PORT, /* nest */ 316 317 __TEAM_ATTR_ITEM_PORT_MAX, 318 TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1, 319 }; 320 321 enum { 322 TEAM_ATTR_PORT_UNSPEC, 323 TEAM_ATTR_PORT_IFINDEX, /* u32 */ 324 TEAM_ATTR_PORT_CHANGED, /* flag */ 325 TEAM_ATTR_PORT_LINKUP, /* flag */ 326 TEAM_ATTR_PORT_SPEED, /* u32 */ 327 TEAM_ATTR_PORT_DUPLEX, /* u8 */ 328 TEAM_ATTR_PORT_REMOVED, /* flag */ 329 330 __TEAM_ATTR_PORT_MAX, 331 TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1, 332 }; 333 334 /* 335 * NETLINK_GENERIC related info 336 */ 337 #define TEAM_GENL_NAME "team" 338 #define TEAM_GENL_VERSION 0x1 339 #define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event" 340 341 #endif /* _LINUX_IF_TEAM_H_ */ 342