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 113d249d4cSJiri Pirko #ifndef _LINUX_IF_TEAM_H_ 123d249d4cSJiri Pirko #define _LINUX_IF_TEAM_H_ 133d249d4cSJiri Pirko 143d249d4cSJiri Pirko #ifdef __KERNEL__ 153d249d4cSJiri Pirko 16bd2d0837SJiri Pirko #include <linux/netpoll.h> 176c85f2bdSJiri Pirko #include <net/sch_generic.h> 18bd2d0837SJiri Pirko 193d249d4cSJiri Pirko struct team_pcpu_stats { 203d249d4cSJiri Pirko u64 rx_packets; 213d249d4cSJiri Pirko u64 rx_bytes; 223d249d4cSJiri Pirko u64 rx_multicast; 233d249d4cSJiri Pirko u64 tx_packets; 243d249d4cSJiri Pirko u64 tx_bytes; 253d249d4cSJiri Pirko struct u64_stats_sync syncp; 263d249d4cSJiri Pirko u32 rx_dropped; 273d249d4cSJiri Pirko u32 tx_dropped; 283d249d4cSJiri Pirko }; 293d249d4cSJiri Pirko 303d249d4cSJiri Pirko struct team; 313d249d4cSJiri Pirko 323d249d4cSJiri Pirko struct team_port { 333d249d4cSJiri Pirko struct net_device *dev; 3419a0b58eSJiri Pirko struct hlist_node hlist; /* node in enabled ports hash list */ 353d249d4cSJiri Pirko struct list_head list; /* node in ordinary list */ 363d249d4cSJiri Pirko struct team *team; 3719a0b58eSJiri Pirko int index; /* index of enabled port. If disabled, it's set to -1 */ 383d249d4cSJiri Pirko 3971472ec1SJiri Pirko bool linkup; /* either state.linkup or user.linkup */ 4071472ec1SJiri Pirko 4171472ec1SJiri Pirko struct { 4271472ec1SJiri Pirko bool linkup; 4371472ec1SJiri Pirko u32 speed; 4471472ec1SJiri Pirko u8 duplex; 4571472ec1SJiri Pirko } state; 4671472ec1SJiri Pirko 4771472ec1SJiri Pirko /* Values set by userspace */ 4871472ec1SJiri Pirko struct { 4971472ec1SJiri Pirko bool linkup; 5071472ec1SJiri Pirko bool linkup_enabled; 5171472ec1SJiri Pirko } user; 5271472ec1SJiri Pirko 5371472ec1SJiri Pirko /* Custom gennetlink interface related flags */ 5471472ec1SJiri Pirko bool changed; 5571472ec1SJiri Pirko bool removed; 5671472ec1SJiri Pirko 573d249d4cSJiri Pirko /* 583d249d4cSJiri Pirko * A place for storing original values of the device before it 593d249d4cSJiri Pirko * become a port. 603d249d4cSJiri Pirko */ 613d249d4cSJiri Pirko struct { 623d249d4cSJiri Pirko unsigned char dev_addr[MAX_ADDR_LEN]; 633d249d4cSJiri Pirko unsigned int mtu; 643d249d4cSJiri Pirko } orig; 653d249d4cSJiri Pirko 66bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 67bd2d0837SJiri Pirko struct netpoll *np; 68bd2d0837SJiri Pirko #endif 69bd2d0837SJiri Pirko 70*a86fc6b7SJiri Pirko s32 priority; /* lower number ~ higher priority */ 715149ee58SJiri Pirko long mode_priv[0]; 723d249d4cSJiri Pirko }; 733d249d4cSJiri Pirko 7468c45042SJiri Pirko static inline bool team_port_enabled(struct team_port *port) 7568c45042SJiri Pirko { 7668c45042SJiri Pirko return port->index != -1; 7768c45042SJiri Pirko } 7868c45042SJiri Pirko 7968c45042SJiri Pirko static inline bool team_port_txable(struct team_port *port) 8068c45042SJiri Pirko { 8168c45042SJiri Pirko return port->linkup && team_port_enabled(port); 8268c45042SJiri Pirko } 8352a4fd77SJiri Pirko 84bd2d0837SJiri Pirko #ifdef CONFIG_NET_POLL_CONTROLLER 85bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 86bd2d0837SJiri Pirko struct sk_buff *skb) 87bd2d0837SJiri Pirko { 88bd2d0837SJiri Pirko struct netpoll *np = port->np; 89bd2d0837SJiri Pirko 90bd2d0837SJiri Pirko if (np) 91bd2d0837SJiri Pirko netpoll_send_skb(np, skb); 92bd2d0837SJiri Pirko } 93bd2d0837SJiri Pirko #else 94bd2d0837SJiri Pirko static inline void team_netpoll_send_skb(struct team_port *port, 95bd2d0837SJiri Pirko struct sk_buff *skb) 96bd2d0837SJiri Pirko { 97bd2d0837SJiri Pirko } 98bd2d0837SJiri Pirko #endif 99bd2d0837SJiri Pirko 100bd2d0837SJiri Pirko static inline int team_dev_queue_xmit(struct team *team, struct team_port *port, 101bd2d0837SJiri Pirko struct sk_buff *skb) 102bd2d0837SJiri Pirko { 1036c85f2bdSJiri Pirko BUILD_BUG_ON(sizeof(skb->queue_mapping) != 1046c85f2bdSJiri Pirko sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); 1056c85f2bdSJiri Pirko skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); 1066c85f2bdSJiri Pirko 107bd2d0837SJiri Pirko skb->dev = port->dev; 108bd2d0837SJiri Pirko if (unlikely(netpoll_tx_running(port->dev))) { 109bd2d0837SJiri Pirko team_netpoll_send_skb(port, skb); 110bd2d0837SJiri Pirko return 0; 111bd2d0837SJiri Pirko } 112bd2d0837SJiri Pirko return dev_queue_xmit(skb); 113bd2d0837SJiri Pirko } 114bd2d0837SJiri Pirko 1153d249d4cSJiri Pirko struct team_mode_ops { 1163d249d4cSJiri Pirko int (*init)(struct team *team); 1173d249d4cSJiri Pirko void (*exit)(struct team *team); 1183d249d4cSJiri Pirko rx_handler_result_t (*receive)(struct team *team, 1193d249d4cSJiri Pirko struct team_port *port, 1203d249d4cSJiri Pirko struct sk_buff *skb); 1213d249d4cSJiri Pirko bool (*transmit)(struct team *team, struct sk_buff *skb); 1223d249d4cSJiri Pirko int (*port_enter)(struct team *team, struct team_port *port); 1233d249d4cSJiri Pirko void (*port_leave)(struct team *team, struct team_port *port); 1243d249d4cSJiri Pirko void (*port_change_mac)(struct team *team, struct team_port *port); 1254bccfd17SJiri Pirko void (*port_enabled)(struct team *team, struct team_port *port); 1264bccfd17SJiri Pirko void (*port_disabled)(struct team *team, struct team_port *port); 1273d249d4cSJiri Pirko }; 1283d249d4cSJiri Pirko 1293d249d4cSJiri Pirko enum team_option_type { 1303d249d4cSJiri Pirko TEAM_OPTION_TYPE_U32, 1313d249d4cSJiri Pirko TEAM_OPTION_TYPE_STRING, 1322615598fSJiri Pirko TEAM_OPTION_TYPE_BINARY, 13314f066baSJiri Pirko TEAM_OPTION_TYPE_BOOL, 13469821638SJiri Pirko TEAM_OPTION_TYPE_S32, 1353d249d4cSJiri Pirko }; 1363d249d4cSJiri Pirko 13785d59a87SJiri Pirko struct team_option_inst_info { 13885d59a87SJiri Pirko u32 array_index; 13985d59a87SJiri Pirko struct team_port *port; /* != NULL if per-port */ 14085d59a87SJiri Pirko }; 14185d59a87SJiri Pirko 14280f7c668SJiri Pirko struct team_gsetter_ctx { 14380f7c668SJiri Pirko union { 14480f7c668SJiri Pirko u32 u32_val; 14580f7c668SJiri Pirko const char *str_val; 14680f7c668SJiri Pirko struct { 14780f7c668SJiri Pirko const void *ptr; 14880f7c668SJiri Pirko u32 len; 14980f7c668SJiri Pirko } bin_val; 15014f066baSJiri Pirko bool bool_val; 15169821638SJiri Pirko s32 s32_val; 15280f7c668SJiri Pirko } data; 15385d59a87SJiri Pirko struct team_option_inst_info *info; 15480f7c668SJiri Pirko }; 15580f7c668SJiri Pirko 1563d249d4cSJiri Pirko struct team_option { 1573d249d4cSJiri Pirko struct list_head list; 1583d249d4cSJiri Pirko const char *name; 15980f7c668SJiri Pirko bool per_port; 160b1303326SJiri Pirko unsigned int array_size; /* != 0 means the option is array */ 1613d249d4cSJiri Pirko enum team_option_type type; 16285d59a87SJiri Pirko int (*init)(struct team *team, struct team_option_inst_info *info); 16380f7c668SJiri Pirko int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); 16480f7c668SJiri Pirko int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); 1653d249d4cSJiri Pirko }; 1663d249d4cSJiri Pirko 1670f1aad2bSJiri Pirko extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info); 1680f1aad2bSJiri Pirko extern void team_options_change_check(struct team *team); 1690f1aad2bSJiri Pirko 1703d249d4cSJiri Pirko struct team_mode { 1713d249d4cSJiri Pirko const char *kind; 1723d249d4cSJiri Pirko struct module *owner; 1733d249d4cSJiri Pirko size_t priv_size; 1745149ee58SJiri Pirko size_t port_priv_size; 1753d249d4cSJiri Pirko const struct team_mode_ops *ops; 1763d249d4cSJiri Pirko }; 1773d249d4cSJiri Pirko 1783d249d4cSJiri Pirko #define TEAM_PORT_HASHBITS 4 1793d249d4cSJiri Pirko #define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS) 1803d249d4cSJiri Pirko 1813d249d4cSJiri Pirko #define TEAM_MODE_PRIV_LONGS 4 1823d249d4cSJiri Pirko #define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS) 1833d249d4cSJiri Pirko 1843d249d4cSJiri Pirko struct team { 1853d249d4cSJiri Pirko struct net_device *dev; /* associated netdevice */ 1863d249d4cSJiri Pirko struct team_pcpu_stats __percpu *pcpu_stats; 1873d249d4cSJiri Pirko 18861dc3461SJiri Pirko struct mutex lock; /* used for overall locking, e.g. port lists write */ 1893d249d4cSJiri Pirko 1903d249d4cSJiri Pirko /* 19119a0b58eSJiri Pirko * List of enabled ports and their count 1923d249d4cSJiri Pirko */ 19319a0b58eSJiri Pirko int en_port_count; 19419a0b58eSJiri Pirko struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES]; 19519a0b58eSJiri Pirko 19619a0b58eSJiri Pirko struct list_head port_list; /* list of all ports */ 1973d249d4cSJiri Pirko 1983d249d4cSJiri Pirko struct list_head option_list; 19980f7c668SJiri Pirko struct list_head option_inst_list; /* list of option instances */ 2003d249d4cSJiri Pirko 2013d249d4cSJiri Pirko const struct team_mode *mode; 2023d249d4cSJiri Pirko struct team_mode_ops ops; 2033d249d4cSJiri Pirko long mode_priv[TEAM_MODE_PRIV_LONGS]; 2043d249d4cSJiri Pirko }; 2053d249d4cSJiri Pirko 2063d249d4cSJiri Pirko static inline struct hlist_head *team_port_index_hash(struct team *team, 2073d249d4cSJiri Pirko int port_index) 2083d249d4cSJiri Pirko { 20919a0b58eSJiri Pirko return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 2103d249d4cSJiri Pirko } 2113d249d4cSJiri Pirko 2123d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index(struct team *team, 2133d249d4cSJiri Pirko int port_index) 2143d249d4cSJiri Pirko { 2153d249d4cSJiri Pirko struct hlist_node *p; 2163d249d4cSJiri Pirko struct team_port *port; 2173d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2183d249d4cSJiri Pirko 2193d249d4cSJiri Pirko hlist_for_each_entry(port, p, head, hlist) 2203d249d4cSJiri Pirko if (port->index == port_index) 2213d249d4cSJiri Pirko return port; 2223d249d4cSJiri Pirko return NULL; 2233d249d4cSJiri Pirko } 2243d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 2253d249d4cSJiri Pirko int port_index) 2263d249d4cSJiri Pirko { 2273d249d4cSJiri Pirko struct hlist_node *p; 2283d249d4cSJiri Pirko struct team_port *port; 2293d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 2303d249d4cSJiri Pirko 2313d249d4cSJiri Pirko hlist_for_each_entry_rcu(port, p, head, hlist) 2323d249d4cSJiri Pirko if (port->index == port_index) 2333d249d4cSJiri Pirko return port; 2343d249d4cSJiri Pirko return NULL; 2353d249d4cSJiri Pirko } 2363d249d4cSJiri Pirko 2373d249d4cSJiri Pirko extern int team_port_set_team_mac(struct team_port *port); 238358b8382SJiri Pirko extern int team_options_register(struct team *team, 239358b8382SJiri Pirko const struct team_option *option, 2403d249d4cSJiri Pirko size_t option_count); 2413d249d4cSJiri Pirko extern void team_options_unregister(struct team *team, 242358b8382SJiri Pirko const struct team_option *option, 2433d249d4cSJiri Pirko size_t option_count); 2440402788aSJiri Pirko extern int team_mode_register(const struct team_mode *mode); 2450402788aSJiri Pirko extern void team_mode_unregister(const struct team_mode *mode); 2463d249d4cSJiri Pirko 2476c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_TX_QUEUES 16 2486c85f2bdSJiri Pirko #define TEAM_DEFAULT_NUM_RX_QUEUES 16 2496c85f2bdSJiri Pirko 2503d249d4cSJiri Pirko #endif /* __KERNEL__ */ 2513d249d4cSJiri Pirko 2523d249d4cSJiri Pirko #define TEAM_STRING_MAX_LEN 32 2533d249d4cSJiri Pirko 2543d249d4cSJiri Pirko /********************************** 2553d249d4cSJiri Pirko * NETLINK_GENERIC netlink family. 2563d249d4cSJiri Pirko **********************************/ 2573d249d4cSJiri Pirko 2583d249d4cSJiri Pirko enum { 2593d249d4cSJiri Pirko TEAM_CMD_NOOP, 2603d249d4cSJiri Pirko TEAM_CMD_OPTIONS_SET, 2613d249d4cSJiri Pirko TEAM_CMD_OPTIONS_GET, 2623d249d4cSJiri Pirko TEAM_CMD_PORT_LIST_GET, 2633d249d4cSJiri Pirko 2643d249d4cSJiri Pirko __TEAM_CMD_MAX, 2653d249d4cSJiri Pirko TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1), 2663d249d4cSJiri Pirko }; 2673d249d4cSJiri Pirko 2683d249d4cSJiri Pirko enum { 2693d249d4cSJiri Pirko TEAM_ATTR_UNSPEC, 2703d249d4cSJiri Pirko TEAM_ATTR_TEAM_IFINDEX, /* u32 */ 2713d249d4cSJiri Pirko TEAM_ATTR_LIST_OPTION, /* nest */ 2723d249d4cSJiri Pirko TEAM_ATTR_LIST_PORT, /* nest */ 2733d249d4cSJiri Pirko 2743d249d4cSJiri Pirko __TEAM_ATTR_MAX, 2753d249d4cSJiri Pirko TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1, 2763d249d4cSJiri Pirko }; 2773d249d4cSJiri Pirko 2783d249d4cSJiri Pirko /* Nested layout of get/set msg: 2793d249d4cSJiri Pirko * 2803d249d4cSJiri Pirko * [TEAM_ATTR_LIST_OPTION] 2813d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_OPTION] 2823d249d4cSJiri Pirko * [TEAM_ATTR_OPTION_*], ... 2833d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_OPTION] 2843d249d4cSJiri Pirko * [TEAM_ATTR_OPTION_*], ... 2853d249d4cSJiri Pirko * ... 2863d249d4cSJiri Pirko * [TEAM_ATTR_LIST_PORT] 2873d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_PORT] 2883d249d4cSJiri Pirko * [TEAM_ATTR_PORT_*], ... 2893d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_PORT] 2903d249d4cSJiri Pirko * [TEAM_ATTR_PORT_*], ... 2913d249d4cSJiri Pirko * ... 2923d249d4cSJiri Pirko */ 2933d249d4cSJiri Pirko 2943d249d4cSJiri Pirko enum { 2953d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION_UNSPEC, 2963d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION, /* nest */ 2973d249d4cSJiri Pirko 2983d249d4cSJiri Pirko __TEAM_ATTR_ITEM_OPTION_MAX, 2993d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1, 3003d249d4cSJiri Pirko }; 3013d249d4cSJiri Pirko 3023d249d4cSJiri Pirko enum { 3033d249d4cSJiri Pirko TEAM_ATTR_OPTION_UNSPEC, 3043d249d4cSJiri Pirko TEAM_ATTR_OPTION_NAME, /* string */ 3053d249d4cSJiri Pirko TEAM_ATTR_OPTION_CHANGED, /* flag */ 3063d249d4cSJiri Pirko TEAM_ATTR_OPTION_TYPE, /* u8 */ 3073d249d4cSJiri Pirko TEAM_ATTR_OPTION_DATA, /* dynamic */ 308b82b9183SJiri Pirko TEAM_ATTR_OPTION_REMOVED, /* flag */ 30980f7c668SJiri Pirko TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */ 310b1303326SJiri Pirko TEAM_ATTR_OPTION_ARRAY_INDEX, /* u32 */ /* for array options */ 3113d249d4cSJiri Pirko 3123d249d4cSJiri Pirko __TEAM_ATTR_OPTION_MAX, 3133d249d4cSJiri Pirko TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1, 3143d249d4cSJiri Pirko }; 3153d249d4cSJiri Pirko 3163d249d4cSJiri Pirko enum { 3173d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT_UNSPEC, 3183d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT, /* nest */ 3193d249d4cSJiri Pirko 3203d249d4cSJiri Pirko __TEAM_ATTR_ITEM_PORT_MAX, 3213d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1, 3223d249d4cSJiri Pirko }; 3233d249d4cSJiri Pirko 3243d249d4cSJiri Pirko enum { 3253d249d4cSJiri Pirko TEAM_ATTR_PORT_UNSPEC, 3263d249d4cSJiri Pirko TEAM_ATTR_PORT_IFINDEX, /* u32 */ 3273d249d4cSJiri Pirko TEAM_ATTR_PORT_CHANGED, /* flag */ 3283d249d4cSJiri Pirko TEAM_ATTR_PORT_LINKUP, /* flag */ 3293d249d4cSJiri Pirko TEAM_ATTR_PORT_SPEED, /* u32 */ 3303d249d4cSJiri Pirko TEAM_ATTR_PORT_DUPLEX, /* u8 */ 331b82b9183SJiri Pirko TEAM_ATTR_PORT_REMOVED, /* flag */ 3323d249d4cSJiri Pirko 3333d249d4cSJiri Pirko __TEAM_ATTR_PORT_MAX, 3343d249d4cSJiri Pirko TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1, 3353d249d4cSJiri Pirko }; 3363d249d4cSJiri Pirko 3373d249d4cSJiri Pirko /* 3383d249d4cSJiri Pirko * NETLINK_GENERIC related info 3393d249d4cSJiri Pirko */ 3403d249d4cSJiri Pirko #define TEAM_GENL_NAME "team" 3413d249d4cSJiri Pirko #define TEAM_GENL_VERSION 0x1 3423d249d4cSJiri Pirko #define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event" 3433d249d4cSJiri Pirko 3443d249d4cSJiri Pirko #endif /* _LINUX_IF_TEAM_H_ */ 345