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 163d249d4cSJiri Pirko struct team_pcpu_stats { 173d249d4cSJiri Pirko u64 rx_packets; 183d249d4cSJiri Pirko u64 rx_bytes; 193d249d4cSJiri Pirko u64 rx_multicast; 203d249d4cSJiri Pirko u64 tx_packets; 213d249d4cSJiri Pirko u64 tx_bytes; 223d249d4cSJiri Pirko struct u64_stats_sync syncp; 233d249d4cSJiri Pirko u32 rx_dropped; 243d249d4cSJiri Pirko u32 tx_dropped; 253d249d4cSJiri Pirko }; 263d249d4cSJiri Pirko 273d249d4cSJiri Pirko struct team; 283d249d4cSJiri Pirko 293d249d4cSJiri Pirko struct team_port { 303d249d4cSJiri Pirko struct net_device *dev; 313d249d4cSJiri Pirko struct hlist_node hlist; /* node in hash list */ 323d249d4cSJiri Pirko struct list_head list; /* node in ordinary list */ 333d249d4cSJiri Pirko struct team *team; 343d249d4cSJiri Pirko int index; 353d249d4cSJiri Pirko 363d249d4cSJiri Pirko /* 373d249d4cSJiri Pirko * A place for storing original values of the device before it 383d249d4cSJiri Pirko * become a port. 393d249d4cSJiri Pirko */ 403d249d4cSJiri Pirko struct { 413d249d4cSJiri Pirko unsigned char dev_addr[MAX_ADDR_LEN]; 423d249d4cSJiri Pirko unsigned int mtu; 433d249d4cSJiri Pirko } orig; 443d249d4cSJiri Pirko 453d249d4cSJiri Pirko bool linkup; 463d249d4cSJiri Pirko u32 speed; 473d249d4cSJiri Pirko u8 duplex; 483d249d4cSJiri Pirko 49b82b9183SJiri Pirko /* Custom gennetlink interface related flags */ 50b82b9183SJiri Pirko bool changed; 51b82b9183SJiri Pirko bool removed; 52b82b9183SJiri Pirko 533d249d4cSJiri Pirko struct rcu_head rcu; 543d249d4cSJiri Pirko }; 553d249d4cSJiri Pirko 563d249d4cSJiri Pirko struct team_mode_ops { 573d249d4cSJiri Pirko int (*init)(struct team *team); 583d249d4cSJiri Pirko void (*exit)(struct team *team); 593d249d4cSJiri Pirko rx_handler_result_t (*receive)(struct team *team, 603d249d4cSJiri Pirko struct team_port *port, 613d249d4cSJiri Pirko struct sk_buff *skb); 623d249d4cSJiri Pirko bool (*transmit)(struct team *team, struct sk_buff *skb); 633d249d4cSJiri Pirko int (*port_enter)(struct team *team, struct team_port *port); 643d249d4cSJiri Pirko void (*port_leave)(struct team *team, struct team_port *port); 653d249d4cSJiri Pirko void (*port_change_mac)(struct team *team, struct team_port *port); 663d249d4cSJiri Pirko }; 673d249d4cSJiri Pirko 683d249d4cSJiri Pirko enum team_option_type { 693d249d4cSJiri Pirko TEAM_OPTION_TYPE_U32, 703d249d4cSJiri Pirko TEAM_OPTION_TYPE_STRING, 712615598fSJiri Pirko TEAM_OPTION_TYPE_BINARY, 723d249d4cSJiri Pirko }; 733d249d4cSJiri Pirko 74*80f7c668SJiri Pirko struct team_gsetter_ctx { 75*80f7c668SJiri Pirko union { 76*80f7c668SJiri Pirko u32 u32_val; 77*80f7c668SJiri Pirko const char *str_val; 78*80f7c668SJiri Pirko struct { 79*80f7c668SJiri Pirko const void *ptr; 80*80f7c668SJiri Pirko u32 len; 81*80f7c668SJiri Pirko } bin_val; 82*80f7c668SJiri Pirko } data; 83*80f7c668SJiri Pirko struct team_port *port; 84*80f7c668SJiri Pirko }; 85*80f7c668SJiri Pirko 863d249d4cSJiri Pirko struct team_option { 873d249d4cSJiri Pirko struct list_head list; 883d249d4cSJiri Pirko const char *name; 89*80f7c668SJiri Pirko bool per_port; 903d249d4cSJiri Pirko enum team_option_type type; 91*80f7c668SJiri Pirko int (*getter)(struct team *team, struct team_gsetter_ctx *ctx); 92*80f7c668SJiri Pirko int (*setter)(struct team *team, struct team_gsetter_ctx *ctx); 933d249d4cSJiri Pirko }; 943d249d4cSJiri Pirko 953d249d4cSJiri Pirko struct team_mode { 963d249d4cSJiri Pirko struct list_head list; 973d249d4cSJiri Pirko const char *kind; 983d249d4cSJiri Pirko struct module *owner; 993d249d4cSJiri Pirko size_t priv_size; 1003d249d4cSJiri Pirko const struct team_mode_ops *ops; 1013d249d4cSJiri Pirko }; 1023d249d4cSJiri Pirko 1033d249d4cSJiri Pirko #define TEAM_PORT_HASHBITS 4 1043d249d4cSJiri Pirko #define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS) 1053d249d4cSJiri Pirko 1063d249d4cSJiri Pirko #define TEAM_MODE_PRIV_LONGS 4 1073d249d4cSJiri Pirko #define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS) 1083d249d4cSJiri Pirko 1093d249d4cSJiri Pirko struct team { 1103d249d4cSJiri Pirko struct net_device *dev; /* associated netdevice */ 1113d249d4cSJiri Pirko struct team_pcpu_stats __percpu *pcpu_stats; 1123d249d4cSJiri Pirko 11361dc3461SJiri Pirko struct mutex lock; /* used for overall locking, e.g. port lists write */ 1143d249d4cSJiri Pirko 1153d249d4cSJiri Pirko /* 1163d249d4cSJiri Pirko * port lists with port count 1173d249d4cSJiri Pirko */ 1183d249d4cSJiri Pirko int port_count; 1193d249d4cSJiri Pirko struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES]; 1203d249d4cSJiri Pirko struct list_head port_list; 1213d249d4cSJiri Pirko 1223d249d4cSJiri Pirko struct list_head option_list; 123*80f7c668SJiri Pirko struct list_head option_inst_list; /* list of option instances */ 1243d249d4cSJiri Pirko 1253d249d4cSJiri Pirko const struct team_mode *mode; 1263d249d4cSJiri Pirko struct team_mode_ops ops; 1273d249d4cSJiri Pirko long mode_priv[TEAM_MODE_PRIV_LONGS]; 1283d249d4cSJiri Pirko }; 1293d249d4cSJiri Pirko 1303d249d4cSJiri Pirko static inline struct hlist_head *team_port_index_hash(struct team *team, 1313d249d4cSJiri Pirko int port_index) 1323d249d4cSJiri Pirko { 1333d249d4cSJiri Pirko return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)]; 1343d249d4cSJiri Pirko } 1353d249d4cSJiri Pirko 1363d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index(struct team *team, 1373d249d4cSJiri Pirko int port_index) 1383d249d4cSJiri Pirko { 1393d249d4cSJiri Pirko struct hlist_node *p; 1403d249d4cSJiri Pirko struct team_port *port; 1413d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 1423d249d4cSJiri Pirko 1433d249d4cSJiri Pirko hlist_for_each_entry(port, p, head, hlist) 1443d249d4cSJiri Pirko if (port->index == port_index) 1453d249d4cSJiri Pirko return port; 1463d249d4cSJiri Pirko return NULL; 1473d249d4cSJiri Pirko } 1483d249d4cSJiri Pirko static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 1493d249d4cSJiri Pirko int port_index) 1503d249d4cSJiri Pirko { 1513d249d4cSJiri Pirko struct hlist_node *p; 1523d249d4cSJiri Pirko struct team_port *port; 1533d249d4cSJiri Pirko struct hlist_head *head = team_port_index_hash(team, port_index); 1543d249d4cSJiri Pirko 1553d249d4cSJiri Pirko hlist_for_each_entry_rcu(port, p, head, hlist) 1563d249d4cSJiri Pirko if (port->index == port_index) 1573d249d4cSJiri Pirko return port; 1583d249d4cSJiri Pirko return NULL; 1593d249d4cSJiri Pirko } 1603d249d4cSJiri Pirko 1613d249d4cSJiri Pirko extern int team_port_set_team_mac(struct team_port *port); 162358b8382SJiri Pirko extern int team_options_register(struct team *team, 163358b8382SJiri Pirko const struct team_option *option, 1643d249d4cSJiri Pirko size_t option_count); 1653d249d4cSJiri Pirko extern void team_options_unregister(struct team *team, 166358b8382SJiri Pirko const struct team_option *option, 1673d249d4cSJiri Pirko size_t option_count); 1683d249d4cSJiri Pirko extern int team_mode_register(struct team_mode *mode); 1693d249d4cSJiri Pirko extern int team_mode_unregister(struct team_mode *mode); 1703d249d4cSJiri Pirko 1713d249d4cSJiri Pirko #endif /* __KERNEL__ */ 1723d249d4cSJiri Pirko 1733d249d4cSJiri Pirko #define TEAM_STRING_MAX_LEN 32 1743d249d4cSJiri Pirko 1753d249d4cSJiri Pirko /********************************** 1763d249d4cSJiri Pirko * NETLINK_GENERIC netlink family. 1773d249d4cSJiri Pirko **********************************/ 1783d249d4cSJiri Pirko 1793d249d4cSJiri Pirko enum { 1803d249d4cSJiri Pirko TEAM_CMD_NOOP, 1813d249d4cSJiri Pirko TEAM_CMD_OPTIONS_SET, 1823d249d4cSJiri Pirko TEAM_CMD_OPTIONS_GET, 1833d249d4cSJiri Pirko TEAM_CMD_PORT_LIST_GET, 1843d249d4cSJiri Pirko 1853d249d4cSJiri Pirko __TEAM_CMD_MAX, 1863d249d4cSJiri Pirko TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1), 1873d249d4cSJiri Pirko }; 1883d249d4cSJiri Pirko 1893d249d4cSJiri Pirko enum { 1903d249d4cSJiri Pirko TEAM_ATTR_UNSPEC, 1913d249d4cSJiri Pirko TEAM_ATTR_TEAM_IFINDEX, /* u32 */ 1923d249d4cSJiri Pirko TEAM_ATTR_LIST_OPTION, /* nest */ 1933d249d4cSJiri Pirko TEAM_ATTR_LIST_PORT, /* nest */ 1943d249d4cSJiri Pirko 1953d249d4cSJiri Pirko __TEAM_ATTR_MAX, 1963d249d4cSJiri Pirko TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1, 1973d249d4cSJiri Pirko }; 1983d249d4cSJiri Pirko 1993d249d4cSJiri Pirko /* Nested layout of get/set msg: 2003d249d4cSJiri Pirko * 2013d249d4cSJiri Pirko * [TEAM_ATTR_LIST_OPTION] 2023d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_OPTION] 2033d249d4cSJiri Pirko * [TEAM_ATTR_OPTION_*], ... 2043d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_OPTION] 2053d249d4cSJiri Pirko * [TEAM_ATTR_OPTION_*], ... 2063d249d4cSJiri Pirko * ... 2073d249d4cSJiri Pirko * [TEAM_ATTR_LIST_PORT] 2083d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_PORT] 2093d249d4cSJiri Pirko * [TEAM_ATTR_PORT_*], ... 2103d249d4cSJiri Pirko * [TEAM_ATTR_ITEM_PORT] 2113d249d4cSJiri Pirko * [TEAM_ATTR_PORT_*], ... 2123d249d4cSJiri Pirko * ... 2133d249d4cSJiri Pirko */ 2143d249d4cSJiri Pirko 2153d249d4cSJiri Pirko enum { 2163d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION_UNSPEC, 2173d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION, /* nest */ 2183d249d4cSJiri Pirko 2193d249d4cSJiri Pirko __TEAM_ATTR_ITEM_OPTION_MAX, 2203d249d4cSJiri Pirko TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1, 2213d249d4cSJiri Pirko }; 2223d249d4cSJiri Pirko 2233d249d4cSJiri Pirko enum { 2243d249d4cSJiri Pirko TEAM_ATTR_OPTION_UNSPEC, 2253d249d4cSJiri Pirko TEAM_ATTR_OPTION_NAME, /* string */ 2263d249d4cSJiri Pirko TEAM_ATTR_OPTION_CHANGED, /* flag */ 2273d249d4cSJiri Pirko TEAM_ATTR_OPTION_TYPE, /* u8 */ 2283d249d4cSJiri Pirko TEAM_ATTR_OPTION_DATA, /* dynamic */ 229b82b9183SJiri Pirko TEAM_ATTR_OPTION_REMOVED, /* flag */ 230*80f7c668SJiri Pirko TEAM_ATTR_OPTION_PORT_IFINDEX, /* u32 */ /* for per-port options */ 2313d249d4cSJiri Pirko 2323d249d4cSJiri Pirko __TEAM_ATTR_OPTION_MAX, 2333d249d4cSJiri Pirko TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1, 2343d249d4cSJiri Pirko }; 2353d249d4cSJiri Pirko 2363d249d4cSJiri Pirko enum { 2373d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT_UNSPEC, 2383d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT, /* nest */ 2393d249d4cSJiri Pirko 2403d249d4cSJiri Pirko __TEAM_ATTR_ITEM_PORT_MAX, 2413d249d4cSJiri Pirko TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1, 2423d249d4cSJiri Pirko }; 2433d249d4cSJiri Pirko 2443d249d4cSJiri Pirko enum { 2453d249d4cSJiri Pirko TEAM_ATTR_PORT_UNSPEC, 2463d249d4cSJiri Pirko TEAM_ATTR_PORT_IFINDEX, /* u32 */ 2473d249d4cSJiri Pirko TEAM_ATTR_PORT_CHANGED, /* flag */ 2483d249d4cSJiri Pirko TEAM_ATTR_PORT_LINKUP, /* flag */ 2493d249d4cSJiri Pirko TEAM_ATTR_PORT_SPEED, /* u32 */ 2503d249d4cSJiri Pirko TEAM_ATTR_PORT_DUPLEX, /* u8 */ 251b82b9183SJiri Pirko TEAM_ATTR_PORT_REMOVED, /* flag */ 2523d249d4cSJiri Pirko 2533d249d4cSJiri Pirko __TEAM_ATTR_PORT_MAX, 2543d249d4cSJiri Pirko TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1, 2553d249d4cSJiri Pirko }; 2563d249d4cSJiri Pirko 2573d249d4cSJiri Pirko /* 2583d249d4cSJiri Pirko * NETLINK_GENERIC related info 2593d249d4cSJiri Pirko */ 2603d249d4cSJiri Pirko #define TEAM_GENL_NAME "team" 2613d249d4cSJiri Pirko #define TEAM_GENL_VERSION 0x1 2623d249d4cSJiri Pirko #define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event" 2633d249d4cSJiri Pirko 2643d249d4cSJiri Pirko #endif /* _LINUX_IF_TEAM_H_ */ 265