blob: fb2872efd0ac19fb1e70a55600ebfdbdf656ebc5 [file] [log] [blame]
/*
* teamd.h - Network team device daemon
* Copyright (C) 2011-2015 Jiri Pirko <jiri@resnulli.us>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _TEAMD_H_
#define _TEAMD_H_
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
#include <libdaemon/dlog.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
#include <jansson.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <team.h>
#include <private/list.h>
#include "config.h"
#ifdef ENABLE_DBUS
#include <dbus/dbus.h>
#endif
#ifdef ENABLE_ZMQ
#include <zmq.h>
#endif
#define teamd_log_err(args...) daemon_log(LOG_ERR, ##args)
#define teamd_log_warn(args...) daemon_log(LOG_WARNING, ##args)
#define teamd_log_info(args...) daemon_log(LOG_INFO, ##args)
#define teamd_log_dbgx(ctx, val, args...) \
({ if (val <= ctx->debug) daemon_log(LOG_DEBUG, ##args); })
#define teamd_log_dbg(ctx, args...) teamd_log_dbgx(ctx, 1, ##args)
static inline void TEAMD_BUG(void)
{
daemon_log(LOG_DEBUG, "BUG: %s:%d\n", __FILE__, __LINE__);
assert(0);
}
static inline void TEAMD_BUG_ON(bool condition)
{
if (condition)
TEAMD_BUG();
}
#ifndef TEAMD_RUN_DIR
#define TEAMD_RUN_DIR "/var/run/teamd/"
#endif
static inline int teamd_make_rundir(void)
{
int ret;
ret = mkdir(TEAMD_RUN_DIR, 0755);
if (ret && errno != EEXIST) {
teamd_log_err("Failed to create directory \"%s\"",
TEAMD_RUN_DIR);
return -errno;
}
return 0;
}
enum teamd_command {
DAEMON_CMD_RUN,
DAEMON_CMD_KILL,
DAEMON_CMD_VERSION,
DAEMON_CMD_HELP,
DAEMON_CMD_CHECK
};
struct teamd_runner;
struct teamd_context;
struct teamd_context {
enum teamd_command cmd;
bool daemonize;
unsigned int debug;
char * log_output;
bool force_recreate;
bool take_over;
bool no_quit_destroy;
bool init_no_ports;
bool pre_add_ports;
char * config_file;
char * config_text;
json_t * config_json;
char * pid_file;
char * team_devname;
char * ident;
char * argv0;
struct team_handle * th;
const struct teamd_runner * runner;
void * runner_priv;
struct list_item port_obj_list;
unsigned int port_obj_list_count;
struct list_item option_watch_list;
struct list_item event_watch_list;
struct list_item state_ops_list;
struct list_item state_val_list;
uint32_t ifindex;
struct team_ifinfo * ifinfo;
char * hwaddr;
uint32_t hwaddr_len;
bool hwaddr_explicit;
struct {
struct list_item callback_list;
int ctrl_pipe_r;
int ctrl_pipe_w;
int err;
} run_loop;
#ifdef ENABLE_DBUS
struct {
bool enabled;
DBusConnection * con;
} dbus;
#endif
#ifdef ENABLE_ZMQ
struct {
bool enabled;
void * context;
void * sock;
char * addr;
} zmq;
#endif
struct {
bool enabled;
int sock;
struct sockaddr_un addr;
struct list_item acc_conn_list;
} usock;
struct {
struct list_item work_list;
int pipe_r;
int pipe_w;
} workq;
};
struct teamd_port {
uint32_t ifindex;
char * ifname;
struct team_port * team_port;
struct team_ifinfo * team_ifinfo;
};
struct teamd_runner {
const char *name;
const char *team_mode_name;
size_t priv_size;
int (*init)(struct teamd_context *ctx, void *priv);
void (*fini)(struct teamd_context *ctx, void *priv);
};
struct teamd_event_watch_ops {
int (*hwaddr_changed)(struct teamd_context *ctx, void *priv);
int (*ifname_changed)(struct teamd_context *ctx, void *priv);
int (*admin_state_changed)(struct teamd_context *ctx, void *priv);
int (*port_added)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
void (*port_removed)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
int (*port_changed)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
int (*port_link_changed)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
int (*port_hwaddr_changed)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
int (*port_ifname_changed)(struct teamd_context *ctx,
struct teamd_port *tdport, void *priv);
int (*port_master_ifindex_changed)(struct teamd_context *ctx,
struct teamd_port *tdport,
void *priv);
int (*option_changed)(struct teamd_context *ctx,
struct team_option *option, void *priv);
char *option_changed_match_name;
};
int teamd_event_port_added(struct teamd_context *ctx,
struct teamd_port *tdport);
void teamd_event_port_removed(struct teamd_context *ctx,
struct teamd_port *tdport);
int teamd_event_port_changed(struct teamd_context *ctx,
struct teamd_port *tdport);
int teamd_event_port_link_changed(struct teamd_context *ctx,
struct teamd_port *tdport);
int teamd_event_option_changed(struct teamd_context *ctx,
struct team_option *option);
int teamd_event_ifinfo_hwaddr_changed(struct teamd_context *ctx,
struct team_ifinfo *ifinfo);
int teamd_event_ifinfo_ifname_changed(struct teamd_context *ctx,
struct team_ifinfo *ifinfo);
int teamd_event_ifinfo_master_ifindex_changed(struct teamd_context *ctx,
struct team_ifinfo *ifinfo);
int teamd_event_ifinfo_admin_state_changed(struct teamd_context *ctx,
struct team_ifinfo *ifinfo);
int teamd_events_init(struct teamd_context *ctx);
void teamd_events_fini(struct teamd_context *ctx);
int teamd_event_watch_register(struct teamd_context *ctx,
const struct teamd_event_watch_ops *ops,
void *priv);
void teamd_event_watch_unregister(struct teamd_context *ctx,
const struct teamd_event_watch_ops *ops,
void *priv);
/* Main loop callbacks */
#define TEAMD_LOOP_FD_EVENT_READ (1 << 0)
#define TEAMD_LOOP_FD_EVENT_WRITE (1 << 1)
#define TEAMD_LOOP_FD_EVENT_EXCEPTION (1 << 2)
#define TEAMD_LOOP_FD_EVENT_MASK (TEAMD_LOOP_FD_EVENT_READ | \
TEAMD_LOOP_FD_EVENT_WRITE | \
TEAMD_LOOP_FD_EVENT_EXCEPTION)
typedef int (*teamd_loop_callback_func_t)(struct teamd_context *ctx,
int events, void *priv);
int teamd_loop_callback_fd_add(struct teamd_context *ctx,
const char *cb_name, void *priv,
teamd_loop_callback_func_t func,
int fd, int fd_event);
int teamd_loop_callback_fd_add_tail(struct teamd_context *ctx,
const char *cb_name, void *priv,
teamd_loop_callback_func_t func,
int fd, int fd_event);
int teamd_loop_callback_timer_add_set(struct teamd_context *ctx,
const char *cb_name, void *priv,
teamd_loop_callback_func_t func,
struct timespec *interval,
struct timespec *initial);
int teamd_loop_callback_timer_add(struct teamd_context *ctx,
const char *cb_name, void *priv,
teamd_loop_callback_func_t func);
int teamd_loop_callback_timer_set(struct teamd_context *ctx,
const char *cb_name, void *priv,
struct timespec *interval,
struct timespec *initial);
void teamd_loop_callback_del(struct teamd_context *ctx, const char *cb_name,
void *priv);
int teamd_loop_callback_enable(struct teamd_context *ctx, const char *cb_name,
void *priv);
int teamd_loop_callback_disable(struct teamd_context *ctx, const char *cb_name,
void *priv);
void teamd_run_loop_quit(struct teamd_context *ctx, int err);
void teamd_run_loop_restart(struct teamd_context *ctx);
int teamd_change_debug_level(struct teamd_context *ctx, unsigned int new_debug);
/* Runner structures */
extern const struct teamd_runner teamd_runner_broadcast;
extern const struct teamd_runner teamd_runner_roundrobin;
extern const struct teamd_runner teamd_runner_random;
extern const struct teamd_runner teamd_runner_activebackup;
extern const struct teamd_runner teamd_runner_loadbalance;
extern const struct teamd_runner teamd_runner_lacp;
struct teamd_port_priv {
int (*init)(struct teamd_context *ctx, struct teamd_port *tdport,
void *this_priv, void *creator_priv);
void (*fini)(struct teamd_context *ctx, struct teamd_port *tdport,
void *this_priv, void *creator_priv);
size_t priv_size;
};
int teamd_port_priv_create_and_get(void **ppriv, struct teamd_port *tdport,
const struct teamd_port_priv *pp,
void *creator_priv);
int teamd_port_priv_create(struct teamd_port *tdport,
const struct teamd_port_priv *pp, void *creator_priv);
void *teamd_get_next_port_priv_by_creator(struct teamd_port *tdport,
void *creator_priv, void *priv);
void *teamd_get_first_port_priv_by_creator(struct teamd_port *tdport,
void *creator_priv);
#define teamd_for_each_port_priv_by_creator(priv, tdport, creator_priv) \
for (priv = teamd_get_next_port_priv_by_creator(tdport, creator_priv, \
NULL); \
priv; \
priv = teamd_get_next_port_priv_by_creator(tdport, creator_priv, \
priv))
int teamd_per_port_init(struct teamd_context *ctx);
void teamd_per_port_fini(struct teamd_context *ctx);
struct teamd_port *teamd_get_port(struct teamd_context *ctx, uint32_t ifindex);
struct teamd_port *teamd_get_port_by_ifname(struct teamd_context *ctx,
const char *ifname);
struct teamd_port *teamd_get_next_tdport(struct teamd_context *ctx,
struct teamd_port *tdport);
#define teamd_for_each_tdport(tdport, ctx) \
for (tdport = teamd_get_next_tdport(ctx, NULL); tdport; \
tdport = teamd_get_next_tdport(ctx, tdport))
static inline bool teamd_has_ports(struct teamd_context *ctx)
{
return !list_empty(&ctx->port_obj_list);
}
static inline unsigned int teamd_port_count(struct teamd_context *ctx)
{
return ctx->port_obj_list_count;
}
int teamd_port_add_ifname(struct teamd_context *ctx, const char *port_name);
int teamd_port_remove_ifname(struct teamd_context *ctx, const char *port_name);
int teamd_port_remove_all(struct teamd_context *ctx);
void teamd_port_obj_remove_all(struct teamd_context *ctx);
int teamd_port_enabled(struct teamd_context *ctx, struct teamd_port *tdport,
bool *enabled);
int teamd_port_prio(struct teamd_context *ctx, struct teamd_port *tdport);
int teamd_port_check_enable(struct teamd_context *ctx,
struct teamd_port *tdport,
bool should_enable, bool should_disable);
static inline bool teamd_port_present(struct teamd_context *ctx,
struct teamd_port *tdport)
{
return team_is_port_present(ctx->th, tdport->team_port);
}
bool teamd_link_watch_port_up(struct teamd_context *ctx,
struct teamd_port *tdport);
void teamd_link_watches_set_forced_active(struct teamd_context *ctx,
bool forced_active);
int teamd_link_watch_init(struct teamd_context *ctx);
void teamd_link_watch_fini(struct teamd_context *ctx);
int teamd_option_watch_init(struct teamd_context *ctx);
void teamd_option_watch_fini(struct teamd_context *ctx);
int teamd_ifinfo_watch_init(struct teamd_context *ctx);
void teamd_ifinfo_watch_fini(struct teamd_context *ctx);
struct teamd_balancer;
int teamd_balancer_init(struct teamd_context *ctx, struct teamd_balancer **ptb);
void teamd_balancer_fini(struct teamd_balancer *tb);
int teamd_balancer_port_added(struct teamd_balancer *tb,
struct teamd_port *tdport);
void teamd_balancer_port_removed(struct teamd_balancer *tb,
struct teamd_port *tdport);
int teamd_hash_func_set(struct teamd_context *ctx);
int teamd_packet_sock_open_type(int type, int *sock_p, const uint32_t ifindex,
const unsigned short family,
const struct sock_fprog *fprog,
const struct sock_fprog *alt_fprog);
int teamd_packet_sock_open(int *sock_p, const uint32_t ifindex,
const unsigned short family,
const struct sock_fprog *fprog,
const struct sock_fprog *alt_fprog);
int teamd_getsockname_hwaddr(int sock, struct sockaddr_ll *addr,
size_t expected_len);
int teamd_sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
int teamd_send(int sockfd, const void *buf, size_t len, int flags);
int teamd_recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t addrlen);
/* Various helpers */
static inline void ms_to_timespec(struct timespec *ts, int ms)
{
ts->tv_sec = ms / 1000;
ts->tv_nsec = (ms % 1000) * 1000000;
}
static inline int timespec_to_ms(struct timespec *ts)
{
return ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
}
static inline bool timespec_is_zero(struct timespec *ts)
{
return !ts->tv_sec && !ts->tv_nsec;
}
#define TEAMD_ENOENT(err) (err == -ENOENT || err == -ENODEV)
#endif /* _TEAMD_H_ */