1*2874c5fdSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */ 23d249d4cSJiri Pirko /* 33d249d4cSJiri Pirko * include/linux/if_team.h - Network team device driver header 43d249d4cSJiri Pirko * Copyright (c) 2011 Jiri Pirko <[email protected]> 53d249d4cSJiri Pirko */ 63d249d4cSJiri Pirko #ifndef _LINUX_IF_TEAM_H_ 73d249d4cSJiri Pirko #define _LINUX_IF_TEAM_H_ 83d249d4cSJiri Pirko 9bd2d0837SJiri Pirko #include <linux/netpoll.h> 106c85f2bdSJiri Pirko #include <net/sch_generic.h> 11fc423ff0SJiri Pirko #include <linux/types.h> 12607ca46eSDavid Howells #include <uapi/linux/if_team.h> 13bd2d0837SJiri Pirko 143d249d4cSJiri Pirko struct team_pcpu_stats { 153d249d4cSJiri Pirko u64 rx_packets; 163d249d4cSJiri Pirko u64 rx_bytes; 173d249d4cSJiri Pirko u64 rx_multicast; 183d249d4cSJiri Pirko u64 tx_packets; 193d249d4cSJiri Pirko u64 tx_bytes; 203d249d4cSJiri Pirko struct u64_stats_sync syncp; 213d249d4cSJiri Pirko u32 rx_dropped; 223d249d4cSJiri Pirko u32 tx_dropped; 23bb63daf9SJarod Wilson u32 rx_nohandler; 243d249d4cSJiri Pirko }; 253d249d4cSJiri Pirko 263d249d4cSJiri Pirko struct team; 273d249d4cSJiri Pirko 283d249d4cSJiri Pirko struct team_port { 293d249d4cSJiri Pirko struct net_device *dev; 3019a0b58eSJiri Pirko struct hlist_node hlist; /* node in enabled ports hash list */ 313d249d4cSJiri Pirko struct list_head list; /* node in ordinary list */ 323d249d4cSJiri Pirko struct team *team; 3319a0b58eSJiri Pirko int index; /* index of enabled port. If disabled, it's set to -1 */ 343d249d4cSJiri Pirko 3571472ec1SJiri Pirko bool linkup; /* either state.linkup or user.linkup */ 3671472ec1SJiri Pirko 3771472ec1SJiri Pirko struct { 3871472ec1SJiri Pirko bool linkup; 3971472ec1SJiri Pirko u32 speed; 4071472ec1SJiri Pirko u8 duplex; 4171472ec1SJiri Pirko } state; 4271472ec1SJiri Pirko 4371472ec1SJiri Pirko /* Values set by userspace */ 4471472ec1SJiri Pirko struct { 4571472ec1SJiri Pirko bool linkup; 4671472ec1SJiri Pirko bool linkup_enabled; 4771472ec1SJiri Pirko } user; 4871472ec1SJiri Pirko 4971472ec1SJiri Pirko /* Custom gennetlink interface related flags */ 5071472ec1SJiri Pirko bool changed; 5171472ec1SJiri Pirko bool removed; 5271472ec1SJiri Pirko 533d249d4cSJiri Pirko /* 543d249d4cSJiri Pirko * A place for storing original values of the device before it 553d249d4cSJiri Pirko * become a port. 563d249d4cSJiri Pirko */ 573d249d4cSJiri Pirko struct { 583d249d4cSJiri Pirko unsigned char dev_addr[MAX_ADDR_LEN]; 593d249d4cSJiri Pirko unsigned int mtu; 603d249d4cSJiri Pirko } orig; 613d249d4cSJiri Pirko 62bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 63bd2d0837SJiri Pirko struct netpoll *np; 64bd2d0837SJiri Pirko #endif 65bd2d0837SJiri Pirko 66a86fc6b7SJiri Pirko s32 priority; /* lower number ~ higher priority */ 678ff5105aSJiri Pirko u16 queue_id; 688ff5105aSJiri Pirko struct list_head qom_list; /* node in queue override mapping list */ 69d80b35beSJiri Pirko struct rcu_head rcu; 705149ee58SJiri Pirko long mode_priv[0]; 713d249d4cSJiri Pirko }; 723d249d4cSJiri Pirko 733443b00eSPetr Machata static inline struct team_port *team_port_get_rcu(const struct net_device *dev) 743443b00eSPetr Machata { 753443b00eSPetr Machata return rcu_dereference(dev->rx_handler_data); 763443b00eSPetr Machata } 773443b00eSPetr Machata 7868c45042SJiri Pirko static inline bool team_port_enabled(struct team_port *port) 7968c45042SJiri Pirko { 8068c45042SJiri Pirko return port->index != -1; 8168c45042SJiri Pirko } 8268c45042SJiri Pirko 8368c45042SJiri Pirko static inline bool team_port_txable(struct team_port *port) 8468c45042SJiri Pirko { 8568c45042SJiri Pirko return port->linkup && team_port_enabled(port); 8668c45042SJiri Pirko } 8752a4fd77SJiri Pirko 88eeed992bSPetr Machata static inline bool team_port_dev_txable(const struct net_device *port_dev) 89eeed992bSPetr Machata { 90eeed992bSPetr Machata struct team_port *port; 91eeed992bSPetr Machata bool txable; 92eeed992bSPetr Machata 93eeed992bSPetr Machata rcu_read_lock(); 94eeed992bSPetr Machata port = team_port_get_rcu(port_dev); 95eeed992bSPetr Machata txable = port ? team_port_txable(port) : false; 96eeed992bSPetr Machata rcu_read_unlock(); 97eeed992bSPetr Machata 98eeed992bSPetr Machata return txable; 99eeed992bSPetr Machata } 100eeed992bSPetr Machata 101bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 102bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 103bd2d0837SJiri Pirko struct sk_buff *skb) 104bd2d0837SJiri Pirko { 105bd2d0837SJiri Pirko struct netpoll *np = port->np; 106bd2d0837SJiri Pirko 107bd2d0837SJiri Pirko if (np) 108bd2d0837SJiri Pirko netpoll_send_skb(np, skb); 109bd2d0837SJiri Pirko } 110bd2d0837SJiri Pirko #else 111bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 112bd2d0837SJiri Pirko struct sk_buff *skb) 113bd2d0837SJiri Pirko { 114bd2d0837SJiri Pirko } 115bd2d0837SJiri Pirko #endif 116bd2d0837SJiri Pirko 1173d249d4cSJiri Pirko struct team_mode_ops { 1183d249d4cSJiri Pirko int (*init)(struct team *team); 1193d249d4cSJiri Pirko void (*exit)(struct team *team); 1203d249d4cSJiri Pirko rx_handler_result_t (*receive)(struct team *team, 1213d249d4cSJiri Pirko struct team_port *port, 1223d249d4cSJiri Pirko struct sk_buff *skb); 1233d249d4cSJiri Pirko bool (*transmit)(struct team *team, struct sk_buff *skb); 1243d249d4cSJiri Pirko int (*port_enter)(struct team *team, struct team_port *port); 1253d249d4cSJiri Pirko void (*port_leave)(struct team *team, struct team_port *port); 1261d76efe1SJiri Pirko void (*port_change_dev_addr)(struct team *team, struct team_port *port); 1274bccfd17SJiri Pirko void (*port_enabled)(struct team *team, struct team_port *port); 1284bccfd17SJiri Pirko void (*port_disabled)(struct team *team, struct team_port *port); 1293d249d4cSJiri Pirko }; 1303d249d4cSJiri Pirko 131acbba0d0SJiri Pirko extern int team_modeop_port_enter(struct team *team, struct team_port *port); 132acbba0d0SJiri Pirko extern void team_modeop_port_change_dev_addr(struct team *team, 133acbba0d0SJiri Pirko struct team_port *port); 134acbba0d0SJiri Pirko 1353d249d4cSJiri Pirko enum team_option_type { 1363d249d4cSJiri Pirko TEAM_OPTION_TYPE_U32, 1373d249d4cSJiri Pirko TEAM_OPTION_TYPE_STRING, 1382615598fSJiri Pirko TEAM_OPTION_TYPE_BINARY, 13914f066baSJiri Pirko TEAM_OPTION_TYPE_BOOL, 14069821638SJiri Pirko TEAM_OPTION_TYPE_S32, 1413d249d4cSJiri Pirko }; 1423d249d4cSJiri Pirko 14385d59a87SJiri Pirko struct team_option_inst_info { 14485d59a87SJiri Pirko u32 array_index; 14585d59a87SJiri Pirko struct team_port *port; /* != NULL if per-port */ 14685d59a87SJiri Pirko }; 14785d59a87SJiri Pirko 14880f7c668SJiri Pirko struct team_gsetter_ctx { 14980f7c668SJiri Pirko union { 15080f7c668SJiri Pirko u32 u32_val; 15180f7c668SJiri Pirko const char *str_val; 15280f7c668SJiri Pirko struct { 15380f7c668SJiri Pirko const void *ptr; 15480f7c668SJiri Pirko u32 len; 15580f7c668SJiri Pirko } bin_val; 15614f066baSJiri Pirko bool bool_val; 15769821638SJiri Pirko s32 s32_val; 15880f7c668SJiri Pirko } data; 15985d59a87SJiri Pirko struct team_option_inst_info *info; 16080f7c668SJiri Pirko }; 16180f7c668SJiri Pirko 1623d249d4cSJiri Pirko struct team_option { 1633d249d4cSJiri Pirko struct list_head list; 1643d249d4cSJiri Pirko const char *name; 16580f7c668SJiri Pirko bool per_port; 166b1303326SJiri Pirko unsigned int array_size; /* != 0 means the option is array */ 1673d249d4cSJiri Pirko enum team_option_type type; 16885d59a87SJiri Pirko int (*init)(struct team *team, struct team_option_inst_info *info); 16980f7c668SJiri Pirko int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); 17080f7c668SJiri Pirko int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); 1713d249d4cSJiri Pirko }; 1723d249d4cSJiri Pirko 1730f1aad2bSJiri Pirko extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info); 1740f1aad2bSJiri Pirko extern void team_options_change_check(struct team *team); 1750f1aad2bSJiri Pirko 1763d249d4cSJiri Pirko struct team_mode { 1773d249d4cSJiri Pirko const char *kind; 1783d249d4cSJiri Pirko struct module *owner; 1793d249d4cSJiri Pirko size_t priv_size; 1805149ee58SJiri Pirko size_t port_priv_size; 1813d249d4cSJiri Pirko const struct team_mode_ops *ops; 1828fd72856SJiri Pirko enum netdev_lag_tx_type lag_tx_type; 1833d249d4cSJiri Pirko }; 1843d249d4cSJiri Pirko 1853d249d4cSJiri Pirko #define TEAM_PORT_HASHBITS 4 1863d249d4cSJiri Pirko #define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS) 1873d249d4cSJiri Pirko 1883d249d4cSJiri Pirko #define TEAM_MODE_PRIV_LONGS 4 1893d249d4cSJiri Pirko #define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS) 1903d249d4cSJiri Pirko 1913d249d4cSJiri Pirko struct team { 1923d249d4cSJiri Pirko struct net_device *dev; /* associated netdevice */ 1933d249d4cSJiri Pirko struct team_pcpu_stats __percpu *pcpu_stats; 1943d249d4cSJiri Pirko 19561dc3461SJiri Pirko struct mutex lock; /* used for overall locking, e.g. port lists write */ 1963d249d4cSJiri Pirko 1973d249d4cSJiri Pirko /* 19819a0b58eSJiri Pirko * List of enabled ports and their count 1993d249d4cSJiri Pirko */ 20019a0b58eSJiri Pirko int en_port_count; 20119a0b58eSJiri Pirko struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES]; 20219a0b58eSJiri Pirko 20319a0b58eSJiri Pirko struct list_head port_list; /* list of all ports */ 2043d249d4cSJiri Pirko 2053d249d4cSJiri Pirko struct list_head option_list; 20680f7c668SJiri Pirko struct list_head option_inst_list; /* list of option instances */ 2073d249d4cSJiri Pirko 2083d249d4cSJiri Pirko const struct team_mode *mode; 2093d249d4cSJiri Pirko struct team_mode_ops ops; 210e185483eSFlavio Leitner bool user_carrier_enabled; 2118ff5105aSJiri Pirko bool queue_override_enabled; 2128ff5105aSJiri Pirko struct list_head *qom_lists; /* array of queue override mapping lists */ 2139d0d68faSJiri Pirko bool port_mtu_change_allowed; 214fc423ff0SJiri Pirko struct { 215fc423ff0SJiri Pirko unsigned int count; 216fc423ff0SJiri Pirko unsigned int interval; /* in ms */ 217fc423ff0SJiri Pirko atomic_t count_pending; 218fc423ff0SJiri Pirko struct delayed_work dw; 219fc423ff0SJiri Pirko } notify_peers; 220492b200eSJiri Pirko struct { 221492b200eSJiri Pirko unsigned int count; 222492b200eSJiri Pirko unsigned int interval; /* in ms */ 223492b200eSJiri Pirko atomic_t count_pending; 224492b200eSJiri Pirko struct delayed_work dw; 225492b200eSJiri Pirko } mcast_rejoin; 2263d249d4cSJiri Pirko long mode_priv[TEAM_MODE_PRIV_LONGS]; 2273d249d4cSJiri Pirko }; 2283d249d4cSJiri Pirko 229e15c3c22SAmerigo Wang static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, 230e15c3c22SAmerigo Wang struct sk_buff *skb) 231e15c3c22SAmerigo Wang { 232e15c3c22SAmerigo Wang BUILD_BUG_ON(sizeof(skb->queue_mapping) != 233e15c3c22SAmerigo Wang sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); 234e15c3c22SAmerigo Wang skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); 235e15c3c22SAmerigo Wang 236e15c3c22SAmerigo Wang skb->dev = port->dev; 237e15c3c22SAmerigo Wang if (unlikely(netpoll_tx_running(team->dev))) { 238e15c3c22SAmerigo Wang team_netpoll_send_skb(port, skb); 239e15c3c22SAmerigo Wang return 0; 240e15c3c22SAmerigo Wang } 241e15c3c22SAmerigo Wang return dev_queue_xmit(skb); 242e15c3c22SAmerigo Wang } 243e15c3c22SAmerigo Wang 2443d249d4cSJiri Pirko static inline struct hlist_head *team_port_index_hash(struct team *team, 2453d249d4cSJiri Pirko int port_index) 2463d249d4cSJiri Pirko { 24719a0b58eSJiri Pirko return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 2483d249d4cSJiri Pirko } 2493d249d4cSJiri Pirko 2503d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index(struct team *team, 2513d249d4cSJiri Pirko int port_index) 2523d249d4cSJiri Pirko { 2533d249d4cSJiri Pirko struct team_port *port; 2543d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2553d249d4cSJiri Pirko 256b67bfe0dSSasha Levin hlist_for_each_entry(port, head, hlist) 2573d249d4cSJiri Pirko if (port->index == port_index) 2583d249d4cSJiri Pirko return port; 2593d249d4cSJiri Pirko return NULL; 2603d249d4cSJiri Pirko } 261735d381fSJiri Pirko 26221d9629aSAlex Sidorenko static inline int team_num_to_port_index(struct team *team, unsigned int num) 263735d381fSJiri Pirko { 2646aa7de05SMark Rutland int en_port_count = READ_ONCE(team->en_port_count); 265735d381fSJiri Pirko 266735d381fSJiri Pirko if (unlikely(!en_port_count)) 267735d381fSJiri Pirko return 0; 268735d381fSJiri Pirko return num % en_port_count; 269735d381fSJiri Pirko } 270735d381fSJiri Pirko 2713d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 2723d249d4cSJiri Pirko int port_index) 2733d249d4cSJiri Pirko { 2743d249d4cSJiri Pirko struct team_port *port; 2753d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2763d249d4cSJiri Pirko 277b67bfe0dSSasha Levin hlist_for_each_entry_rcu(port, head, hlist) 2783d249d4cSJiri Pirko if (port->index == port_index) 2793d249d4cSJiri Pirko return port; 2803d249d4cSJiri Pirko return NULL; 2813d249d4cSJiri Pirko } 2823d249d4cSJiri Pirko 283753f9939SJiri Pirko static inline struct team_port * 284753f9939SJiri Pirko team_get_first_port_txable_rcu(struct team *team, struct team_port *port) 285753f9939SJiri Pirko { 286753f9939SJiri Pirko struct team_port *cur; 287753f9939SJiri Pirko 288753f9939SJiri Pirko if (likely(team_port_txable(port))) 289753f9939SJiri Pirko return port; 290753f9939SJiri Pirko cur = port; 291753f9939SJiri Pirko list_for_each_entry_continue_rcu(cur, &team->port_list, list) 292b79462a8SJiri Pirko if (team_port_txable(cur)) 293753f9939SJiri Pirko return cur; 294753f9939SJiri Pirko list_for_each_entry_rcu(cur, &team->port_list, list) { 295753f9939SJiri Pirko if (cur == port) 296753f9939SJiri Pirko break; 297b79462a8SJiri Pirko if (team_port_txable(cur)) 298753f9939SJiri Pirko return cur; 299753f9939SJiri Pirko } 300753f9939SJiri Pirko return NULL; 301753f9939SJiri Pirko } 302753f9939SJiri Pirko 303358b8382SJiri Pirko extern int team_options_register(struct team *team, 304358b8382SJiri Pirko const struct team_option *option, 3053d249d4cSJiri Pirko size_t option_count); 3063d249d4cSJiri Pirko extern void team_options_unregister(struct team *team, 307358b8382SJiri Pirko const struct team_option *option, 3083d249d4cSJiri Pirko size_t option_count); 3090402788aSJiri Pirko extern int team_mode_register(const struct team_mode *mode); 3100402788aSJiri Pirko extern void team_mode_unregister(const struct team_mode *mode); 3113d249d4cSJiri Pirko 3126c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_TX_QUEUES 16 3136c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_RX_QUEUES 16 3146c85f2bdSJiri Pirko 3153a5f8997SZhang Shengju #define MODULE_ALIAS_TEAM_MODE(kind) MODULE_ALIAS("team-mode-" kind) 3163a5f8997SZhang Shengju 3173d249d4cSJiri Pirko #endif /* _LINUX_IF_TEAM_H_ */ 318