linux/include/linux/if_team.h
<<
>>
Prefs
   1/*
   2 * include/linux/if_team.h - Network team device driver header
   3 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
   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#ifndef _LINUX_IF_TEAM_H_
  11#define _LINUX_IF_TEAM_H_
  12
  13#include <linux/netpoll.h>
  14#include <net/sch_generic.h>
  15#include <linux/types.h>
  16#include <uapi/linux/if_team.h>
  17
  18struct team_pcpu_stats {
  19        u64                     rx_packets;
  20        u64                     rx_bytes;
  21        u64                     rx_multicast;
  22        u64                     tx_packets;
  23        u64                     tx_bytes;
  24        struct u64_stats_sync   syncp;
  25        u32                     rx_dropped;
  26        u32                     tx_dropped;
  27        u32                     rx_nohandler;
  28};
  29
  30struct team;
  31
  32struct 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        s32 priority; /* lower number ~ higher priority */
  71        u16 queue_id;
  72        struct list_head qom_list; /* node in queue override mapping list */
  73        struct rcu_head rcu;
  74        long mode_priv[0];
  75};
  76
  77static inline struct team_port *team_port_get_rcu(const struct net_device *dev)
  78{
  79        return rcu_dereference(dev->rx_handler_data);
  80}
  81
  82static inline bool team_port_enabled(struct team_port *port)
  83{
  84        return port->index != -1;
  85}
  86
  87static inline bool team_port_txable(struct team_port *port)
  88{
  89        return port->linkup && team_port_enabled(port);
  90}
  91
  92static inline bool team_port_dev_txable(const struct net_device *port_dev)
  93{
  94        struct team_port *port;
  95        bool txable;
  96
  97        rcu_read_lock();
  98        port = team_port_get_rcu(port_dev);
  99        txable = port ? team_port_txable(port) : false;
 100        rcu_read_unlock();
 101
 102        return txable;
 103}
 104
 105#ifdef CONFIG_NET_POLL_CONTROLLER
 106static inline void team_netpoll_send_skb(struct team_port *port,
 107                                         struct sk_buff *skb)
 108{
 109        struct netpoll *np = port->np;
 110
 111        if (np)
 112                netpoll_send_skb(np, skb);
 113}
 114#else
 115static inline void team_netpoll_send_skb(struct team_port *port,
 116                                         struct sk_buff *skb)
 117{
 118}
 119#endif
 120
 121struct team_mode_ops {
 122        int (*init)(struct team *team);
 123        void (*exit)(struct team *team);
 124        rx_handler_result_t (*receive)(struct team *team,
 125                                       struct team_port *port,
 126                                       struct sk_buff *skb);
 127        bool (*transmit)(struct team *team, struct sk_buff *skb);
 128        int (*port_enter)(struct team *team, struct team_port *port);
 129        void (*port_leave)(struct team *team, struct team_port *port);
 130        void (*port_change_dev_addr)(struct team *team, struct team_port *port);
 131        void (*port_enabled)(struct team *team, struct team_port *port);
 132        void (*port_disabled)(struct team *team, struct team_port *port);
 133};
 134
 135extern int team_modeop_port_enter(struct team *team, struct team_port *port);
 136extern void team_modeop_port_change_dev_addr(struct team *team,
 137                                             struct team_port *port);
 138
 139enum team_option_type {
 140        TEAM_OPTION_TYPE_U32,
 141        TEAM_OPTION_TYPE_STRING,
 142        TEAM_OPTION_TYPE_BINARY,
 143        TEAM_OPTION_TYPE_BOOL,
 144        TEAM_OPTION_TYPE_S32,
 145};
 146
 147struct team_option_inst_info {
 148        u32 array_index;
 149        struct team_port *port; /* != NULL if per-port */
 150};
 151
 152struct team_gsetter_ctx {
 153        union {
 154                u32 u32_val;
 155                const char *str_val;
 156                struct {
 157                        const void *ptr;
 158                        u32 len;
 159                } bin_val;
 160                bool bool_val;
 161                s32 s32_val;
 162        } data;
 163        struct team_option_inst_info *info;
 164};
 165
 166struct team_option {
 167        struct list_head list;
 168        const char *name;
 169        bool per_port;
 170        unsigned int array_size; /* != 0 means the option is array */
 171        enum team_option_type type;
 172        int (*init)(struct team *team, struct team_option_inst_info *info);
 173        int (*getter)(struct team *team, struct team_gsetter_ctx *ctx);
 174        int (*setter)(struct team *team, struct team_gsetter_ctx *ctx);
 175};
 176
 177extern void team_option_inst_set_change(struct team_option_inst_info *opt_inst_info);
 178extern void team_options_change_check(struct team *team);
 179
 180struct team_mode {
 181        const char *kind;
 182        struct module *owner;
 183        size_t priv_size;
 184        size_t port_priv_size;
 185        const struct team_mode_ops *ops;
 186        enum netdev_lag_tx_type lag_tx_type;
 187};
 188
 189#define TEAM_PORT_HASHBITS 4
 190#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
 191
 192#define TEAM_MODE_PRIV_LONGS 4
 193#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
 194
 195struct team {
 196        struct net_device *dev; /* associated netdevice */
 197        struct team_pcpu_stats __percpu *pcpu_stats;
 198
 199        struct mutex lock; /* used for overall locking, e.g. port lists write */
 200
 201        /*
 202         * List of enabled ports and their count
 203         */
 204        int en_port_count;
 205        struct hlist_head en_port_hlist[TEAM_PORT_HASHENTRIES];
 206
 207        struct list_head port_list; /* list of all ports */
 208
 209        struct list_head option_list;
 210        struct list_head option_inst_list; /* list of option instances */
 211
 212        const struct team_mode *mode;
 213        struct team_mode_ops ops;
 214        bool user_carrier_enabled;
 215        bool queue_override_enabled;
 216        struct list_head *qom_lists; /* array of queue override mapping lists */
 217        bool port_mtu_change_allowed;
 218        struct {
 219                unsigned int count;
 220                unsigned int interval; /* in ms */
 221                atomic_t count_pending;
 222                struct delayed_work dw;
 223        } notify_peers;
 224        struct {
 225                unsigned int count;
 226                unsigned int interval; /* in ms */
 227                atomic_t count_pending;
 228                struct delayed_work dw;
 229        } mcast_rejoin;
 230        long mode_priv[TEAM_MODE_PRIV_LONGS];
 231};
 232
 233static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
 234                                      struct sk_buff *skb)
 235{
 236        BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
 237                     sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
 238        skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
 239
 240        skb->dev = port->dev;
 241        if (unlikely(netpoll_tx_running(team->dev))) {
 242                team_netpoll_send_skb(port, skb);
 243                return 0;
 244        }
 245        return dev_queue_xmit(skb);
 246}
 247
 248static inline struct hlist_head *team_port_index_hash(struct team *team,
 249                                                      int port_index)
 250{
 251        return &team->en_port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
 252}
 253
 254static inline struct team_port *team_get_port_by_index(struct team *team,
 255                                                       int port_index)
 256{
 257        struct team_port *port;
 258        struct hlist_head *head = team_port_index_hash(team, port_index);
 259
 260        hlist_for_each_entry(port, head, hlist)
 261                if (port->index == port_index)
 262                        return port;
 263        return NULL;
 264}
 265
 266static inline int team_num_to_port_index(struct team *team, unsigned int num)
 267{
 268        int en_port_count = READ_ONCE(team->en_port_count);
 269
 270        if (unlikely(!en_port_count))
 271                return 0;
 272        return num % en_port_count;
 273}
 274
 275static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
 276                                                           int port_index)
 277{
 278        struct team_port *port;
 279        struct hlist_head *head = team_port_index_hash(team, port_index);
 280
 281        hlist_for_each_entry_rcu(port, head, hlist)
 282                if (port->index == port_index)
 283                        return port;
 284        return NULL;
 285}
 286
 287static inline struct team_port *
 288team_get_first_port_txable_rcu(struct team *team, struct team_port *port)
 289{
 290        struct team_port *cur;
 291
 292        if (likely(team_port_txable(port)))
 293                return port;
 294        cur = port;
 295        list_for_each_entry_continue_rcu(cur, &team->port_list, list)
 296                if (team_port_txable(cur))
 297                        return cur;
 298        list_for_each_entry_rcu(cur, &team->port_list, list) {
 299                if (cur == port)
 300                        break;
 301                if (team_port_txable(cur))
 302                        return cur;
 303        }
 304        return NULL;
 305}
 306
 307extern int team_options_register(struct team *team,
 308                                 const struct team_option *option,
 309                                 size_t option_count);
 310extern void team_options_unregister(struct team *team,
 311                                    const struct team_option *option,
 312                                    size_t option_count);
 313extern int team_mode_register(const struct team_mode *mode);
 314extern void team_mode_unregister(const struct team_mode *mode);
 315
 316#define TEAM_DEFAULT_NUM_TX_QUEUES 16
 317#define TEAM_DEFAULT_NUM_RX_QUEUES 16
 318
 319#define MODULE_ALIAS_TEAM_MODE(kind) MODULE_ALIAS("team-mode-" kind)
 320
 321#endif /* _LINUX_IF_TEAM_H_ */
 322