13d249d4cSJiri Pirko /* 23d249d4cSJiri Pirko * include/linux/if_team.h - Network team device driver header 33d249d4cSJiri Pirko * Copyright (c) 2011 Jiri Pirko <[email protected]> 43d249d4cSJiri Pirko * 53d249d4cSJiri Pirko * This program is free software; you can redistribute it and/or modify 63d249d4cSJiri Pirko * it under the terms of the GNU General Public License as published by 73d249d4cSJiri Pirko * the Free Software Foundation; either version 2 of the License, or 83d249d4cSJiri Pirko * (at your option) any later version. 93d249d4cSJiri Pirko */ 103d249d4cSJiri Pirko #ifndef _LINUX_IF_TEAM_H_ 113d249d4cSJiri Pirko #define _LINUX_IF_TEAM_H_ 123d249d4cSJiri Pirko 133d249d4cSJiri Pirko 14bd2d0837SJiri Pirko #include <linux/netpoll.h> 156c85f2bdSJiri Pirko #include <net/sch_generic.h> 16607ca46eSDavid Howells #include <uapi/linux/if_team.h> 17bd2d0837SJiri Pirko 183d249d4cSJiri Pirko struct team_pcpu_stats { 193d249d4cSJiri Pirko u64 rx_packets; 203d249d4cSJiri Pirko u64 rx_bytes; 213d249d4cSJiri Pirko u64 rx_multicast; 223d249d4cSJiri Pirko u64 tx_packets; 233d249d4cSJiri Pirko u64 tx_bytes; 243d249d4cSJiri Pirko struct u64_stats_sync syncp; 253d249d4cSJiri Pirko u32 rx_dropped; 263d249d4cSJiri Pirko u32 tx_dropped; 273d249d4cSJiri Pirko }; 283d249d4cSJiri Pirko 293d249d4cSJiri Pirko struct team; 303d249d4cSJiri Pirko 313d249d4cSJiri Pirko struct team_port { 323d249d4cSJiri Pirko struct net_device *dev; 3319a0b58eSJiri Pirko struct hlist_node hlist; /* node in enabled ports hash list */ 343d249d4cSJiri Pirko struct list_head list; /* node in ordinary list */ 353d249d4cSJiri Pirko struct team *team; 3619a0b58eSJiri Pirko int index; /* index of enabled port. If disabled, it's set to -1 */ 373d249d4cSJiri Pirko 3871472ec1SJiri Pirko bool linkup; /* either state.linkup or user.linkup */ 3971472ec1SJiri Pirko 4071472ec1SJiri Pirko struct { 4171472ec1SJiri Pirko bool linkup; 4271472ec1SJiri Pirko u32 speed; 4371472ec1SJiri Pirko u8 duplex; 4471472ec1SJiri Pirko } state; 4571472ec1SJiri Pirko 4671472ec1SJiri Pirko /* Values set by userspace */ 4771472ec1SJiri Pirko struct { 4871472ec1SJiri Pirko bool linkup; 4971472ec1SJiri Pirko bool linkup_enabled; 5071472ec1SJiri Pirko } user; 5171472ec1SJiri Pirko 5271472ec1SJiri Pirko /* Custom gennetlink interface related flags */ 5371472ec1SJiri Pirko bool changed; 5471472ec1SJiri Pirko bool removed; 5571472ec1SJiri Pirko 563d249d4cSJiri Pirko /* 573d249d4cSJiri Pirko * A place for storing original values of the device before it 583d249d4cSJiri Pirko * become a port. 593d249d4cSJiri Pirko */ 603d249d4cSJiri Pirko struct { 613d249d4cSJiri Pirko unsigned char dev_addr[MAX_ADDR_LEN]; 623d249d4cSJiri Pirko unsigned int mtu; 633d249d4cSJiri Pirko } orig; 643d249d4cSJiri Pirko 65bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 66bd2d0837SJiri Pirko struct netpoll *np; 67bd2d0837SJiri Pirko #endif 68bd2d0837SJiri Pirko 69a86fc6b7SJiri Pirko s32 priority; /* lower number ~ higher priority */ 708ff5105aSJiri Pirko u16 queue_id; 718ff5105aSJiri Pirko struct list_head qom_list; /* node in queue override mapping list */ 725149ee58SJiri Pirko long mode_priv[0]; 733d249d4cSJiri Pirko }; 743d249d4cSJiri Pirko 7568c45042SJiri Pirko static inline bool team_port_enabled(struct team_port *port) 7668c45042SJiri Pirko { 7768c45042SJiri Pirko return port->index != -1; 7868c45042SJiri Pirko } 7968c45042SJiri Pirko 8068c45042SJiri Pirko static inline bool team_port_txable(struct team_port *port) 8168c45042SJiri Pirko { 8268c45042SJiri Pirko return port->linkup && team_port_enabled(port); 8368c45042SJiri Pirko } 8452a4fd77SJiri Pirko 85bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 86bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 87bd2d0837SJiri Pirko struct sk_buff *skb) 88bd2d0837SJiri Pirko { 89bd2d0837SJiri Pirko struct netpoll *np = port->np; 90bd2d0837SJiri Pirko 91bd2d0837SJiri Pirko if (np) 92bd2d0837SJiri Pirko netpoll_send_skb(np, skb); 93bd2d0837SJiri Pirko } 94bd2d0837SJiri Pirko #else 95bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 96bd2d0837SJiri Pirko struct sk_buff *skb) 97bd2d0837SJiri Pirko { 98bd2d0837SJiri Pirko } 99bd2d0837SJiri Pirko #endif 100bd2d0837SJiri Pirko 1013d249d4cSJiri Pirko struct team_mode_ops { 1023d249d4cSJiri Pirko int (*init)(struct team *team); 1033d249d4cSJiri Pirko void (*exit)(struct team *team); 1043d249d4cSJiri Pirko rx_handler_result_t (*receive)(struct team *team, 1053d249d4cSJiri Pirko struct team_port *port, 1063d249d4cSJiri Pirko struct sk_buff *skb); 1073d249d4cSJiri Pirko bool (*transmit)(struct team *team, struct sk_buff *skb); 1083d249d4cSJiri Pirko int (*port_enter)(struct team *team, struct team_port *port); 1093d249d4cSJiri Pirko void (*port_leave)(struct team *team, struct team_port *port); 1101d76efe1SJiri Pirko void (*port_change_dev_addr)(struct team *team, struct team_port *port); 1114bccfd17SJiri Pirko void (*port_enabled)(struct team *team, struct team_port *port); 1124bccfd17SJiri Pirko void (*port_disabled)(struct team *team, struct team_port *port); 1133d249d4cSJiri Pirko }; 1143d249d4cSJiri Pirko 115acbba0d0SJiri Pirko extern int team_modeop_port_enter(struct team *team, struct team_port *port); 116acbba0d0SJiri Pirko extern void team_modeop_port_change_dev_addr(struct team *team, 117acbba0d0SJiri Pirko struct team_port *port); 118acbba0d0SJiri Pirko 1193d249d4cSJiri Pirko enum team_option_type { 1203d249d4cSJiri Pirko TEAM_OPTION_TYPE_U32, 1213d249d4cSJiri Pirko TEAM_OPTION_TYPE_STRING, 1222615598fSJiri Pirko TEAM_OPTION_TYPE_BINARY, 12314f066baSJiri Pirko TEAM_OPTION_TYPE_BOOL, 12469821638SJiri Pirko TEAM_OPTION_TYPE_S32, 1253d249d4cSJiri Pirko }; 1263d249d4cSJiri Pirko 12785d59a87SJiri Pirko struct team_option_inst_info { 12885d59a87SJiri Pirko u32 array_index; 12985d59a87SJiri Pirko struct team_port *port; /* != NULL if per-port */ 13085d59a87SJiri Pirko }; 13185d59a87SJiri Pirko 13280f7c668SJiri Pirko struct team_gsetter_ctx { 13380f7c668SJiri Pirko union { 13480f7c668SJiri Pirko u32 u32_val; 13580f7c668SJiri Pirko const char *str_val; 13680f7c668SJiri Pirko struct { 13780f7c668SJiri Pirko const void *ptr; 13880f7c668SJiri Pirko u32 len; 13980f7c668SJiri Pirko } bin_val; 14014f066baSJiri Pirko bool bool_val; 14169821638SJiri Pirko s32 s32_val; 14280f7c668SJiri Pirko } data; 14385d59a87SJiri Pirko struct team_option_inst_info *info; 14480f7c668SJiri Pirko }; 14580f7c668SJiri Pirko 1463d249d4cSJiri Pirko struct team_option { 1473d249d4cSJiri Pirko struct list_head list; 1483d249d4cSJiri Pirko const char *name; 14980f7c668SJiri Pirko bool per_port; 150b1303326SJiri Pirko unsigned int array_size; /* != 0 means the option is array */ 1513d249d4cSJiri Pirko enum team_option_type type; 15285d59a87SJiri Pirko int (*init)(struct team *team, struct team_option_inst_info *info); 15380f7c668SJiri Pirko int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); 15480f7c668SJiri Pirko int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); 1553d249d4cSJiri Pirko }; 1563d249d4cSJiri Pirko 1570f1aad2bSJiri Pirko extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info); 1580f1aad2bSJiri Pirko extern void team_options_change_check(struct team *team); 1590f1aad2bSJiri Pirko 1603d249d4cSJiri Pirko struct team_mode { 1613d249d4cSJiri Pirko const char *kind; 1623d249d4cSJiri Pirko struct module *owner; 1633d249d4cSJiri Pirko size_t priv_size; 1645149ee58SJiri Pirko size_t port_priv_size; 1653d249d4cSJiri Pirko const struct team_mode_ops *ops; 1663d249d4cSJiri Pirko }; 1673d249d4cSJiri Pirko 1683d249d4cSJiri Pirko #define TEAM_PORT_HASHBITS 4 1693d249d4cSJiri Pirko #define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS) 1703d249d4cSJiri Pirko 1713d249d4cSJiri Pirko #define TEAM_MODE_PRIV_LONGS 4 1723d249d4cSJiri Pirko #define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS) 1733d249d4cSJiri Pirko 1743d249d4cSJiri Pirko struct team { 1753d249d4cSJiri Pirko struct net_device *dev; /* associated netdevice */ 1763d249d4cSJiri Pirko struct team_pcpu_stats __percpu *pcpu_stats; 1773d249d4cSJiri Pirko 17861dc3461SJiri Pirko struct mutex lock; /* used for overall locking, e.g. port lists write */ 1793d249d4cSJiri Pirko 1803d249d4cSJiri Pirko /* 18119a0b58eSJiri Pirko * List of enabled ports and their count 1823d249d4cSJiri Pirko */ 18319a0b58eSJiri Pirko int en_port_count; 18419a0b58eSJiri Pirko struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES]; 18519a0b58eSJiri Pirko 18619a0b58eSJiri Pirko struct list_head port_list; /* list of all ports */ 1873d249d4cSJiri Pirko 1883d249d4cSJiri Pirko struct list_head option_list; 18980f7c668SJiri Pirko struct list_head option_inst_list; /* list of option instances */ 1903d249d4cSJiri Pirko 1913d249d4cSJiri Pirko const struct team_mode *mode; 1923d249d4cSJiri Pirko struct team_mode_ops ops; 193e185483eSFlavio Leitner bool user_carrier_enabled; 1948ff5105aSJiri Pirko bool queue_override_enabled; 1958ff5105aSJiri Pirko struct list_head *qom_lists; /* array of queue override mapping lists */ 1963d249d4cSJiri Pirko long mode_priv[TEAM_MODE_PRIV_LONGS]; 1973d249d4cSJiri Pirko }; 1983d249d4cSJiri Pirko 199e15c3c22SAmerigo Wang static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, 200e15c3c22SAmerigo Wang struct sk_buff *skb) 201e15c3c22SAmerigo Wang { 202e15c3c22SAmerigo Wang BUILD_BUG_ON(sizeof(skb->queue_mapping) != 203e15c3c22SAmerigo Wang sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); 204e15c3c22SAmerigo Wang skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); 205e15c3c22SAmerigo Wang 206e15c3c22SAmerigo Wang skb->dev = port->dev; 207e15c3c22SAmerigo Wang if (unlikely(netpoll_tx_running(team->dev))) { 208e15c3c22SAmerigo Wang team_netpoll_send_skb(port, skb); 209e15c3c22SAmerigo Wang return 0; 210e15c3c22SAmerigo Wang } 211e15c3c22SAmerigo Wang return dev_queue_xmit(skb); 212e15c3c22SAmerigo Wang } 213e15c3c22SAmerigo Wang 2143d249d4cSJiri Pirko static inline struct hlist_head *team_port_index_hash(struct team *team, 2153d249d4cSJiri Pirko int port_index) 2163d249d4cSJiri Pirko { 21719a0b58eSJiri Pirko return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 2183d249d4cSJiri Pirko } 2193d249d4cSJiri Pirko 2203d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index(struct team *team, 2213d249d4cSJiri Pirko int port_index) 2223d249d4cSJiri Pirko { 2233d249d4cSJiri Pirko struct team_port *port; 2243d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2253d249d4cSJiri Pirko 226b67bfe0dSSasha Levin hlist_for_each_entry(port, head, hlist) 2273d249d4cSJiri Pirko if (port->index == port_index) 2283d249d4cSJiri Pirko return port; 2293d249d4cSJiri Pirko return NULL; 2303d249d4cSJiri Pirko } 2313d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 2323d249d4cSJiri Pirko int port_index) 2333d249d4cSJiri Pirko { 2343d249d4cSJiri Pirko struct team_port *port; 2353d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2363d249d4cSJiri Pirko 237b67bfe0dSSasha Levin hlist_for_each_entry_rcu(port, head, hlist) 2383d249d4cSJiri Pirko if (port->index == port_index) 2393d249d4cSJiri Pirko return port; 2403d249d4cSJiri Pirko return NULL; 2413d249d4cSJiri Pirko } 2423d249d4cSJiri Pirko 243*753f9939SJiri Pirko static inline struct team_port * 244*753f9939SJiri Pirko team_get_first_port_txable_rcu(struct team *team, struct team_port *port) 245*753f9939SJiri Pirko { 246*753f9939SJiri Pirko struct team_port *cur; 247*753f9939SJiri Pirko 248*753f9939SJiri Pirko if (likely(team_port_txable(port))) 249*753f9939SJiri Pirko return port; 250*753f9939SJiri Pirko cur = port; 251*753f9939SJiri Pirko list_for_each_entry_continue_rcu(cur, &team->port_list, list) 252*753f9939SJiri Pirko if (team_port_txable(port)) 253*753f9939SJiri Pirko return cur; 254*753f9939SJiri Pirko list_for_each_entry_rcu(cur, &team->port_list, list) { 255*753f9939SJiri Pirko if (cur == port) 256*753f9939SJiri Pirko break; 257*753f9939SJiri Pirko if (team_port_txable(port)) 258*753f9939SJiri Pirko return cur; 259*753f9939SJiri Pirko } 260*753f9939SJiri Pirko return NULL; 261*753f9939SJiri Pirko } 262*753f9939SJiri Pirko 263358b8382SJiri Pirko extern int team_options_register(struct team *team, 264358b8382SJiri Pirko const struct team_option *option, 2653d249d4cSJiri Pirko size_t option_count); 2663d249d4cSJiri Pirko extern void team_options_unregister(struct team *team, 267358b8382SJiri Pirko const struct team_option *option, 2683d249d4cSJiri Pirko size_t option_count); 2690402788aSJiri Pirko extern int team_mode_register(const struct team_mode *mode); 2700402788aSJiri Pirko extern void team_mode_unregister(const struct team_mode *mode); 2713d249d4cSJiri Pirko 2726c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_TX_QUEUES 16 2736c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_RX_QUEUES 16 2746c85f2bdSJiri Pirko 2753d249d4cSJiri Pirko #endif /* _LINUX_IF_TEAM_H_ */ 276