Blame teamd/teamd_lw_psr.c

Packit cac203
/*
Packit cac203
 *   teamd_lw_psr.c - Team port periodic send/receive link watcher
Packit cac203
 *   Copyright (C) 2012-2015 Jiri Pirko <jiri@resnulli.us>
Packit cac203
 *   Copyright (C) 2014 Erik Hugne <erik.hugne@ericsson.com>
Packit cac203
 *
Packit cac203
 *   This library is free software; you can redistribute it and/or
Packit cac203
 *   modify it under the terms of the GNU Lesser General Public
Packit cac203
 *   License as published by the Free Software Foundation; either
Packit cac203
 *   version 2.1 of the License, or (at your option) any later version.
Packit cac203
 *
Packit cac203
 *   This library is distributed in the hope that it will be useful,
Packit cac203
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cac203
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit cac203
 *   Lesser General Public License for more details.
Packit cac203
 *
Packit cac203
 *   You should have received a copy of the GNU Lesser General Public
Packit cac203
 *   License along with this library; if not, write to the Free Software
Packit cac203
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit cac203
 */
Packit cac203
Packit cac203
#include <private/misc.h>
Packit cac203
#include "teamd.h"
Packit cac203
#include "teamd_link_watch.h"
Packit cac203
#include "teamd_config.h"
Packit cac203
Packit cac203
/*
Packit cac203
 * Generic periodic send/receive link watch "template"
Packit cac203
 */
Packit cac203
Packit cac203
static const struct timespec lw_psr_default_init_wait = { 0, 1 };
Packit cac203
#define LW_PSR_DEFAULT_INTERVAL   1000
Packit cac203
#define LW_PSR_DEFAULT_MISSED_MAX 3
Packit cac203
Packit cac203
#define LW_PERIODIC_CB_NAME "lw_periodic"
Packit cac203
static int lw_psr_callback_periodic(struct teamd_context *ctx, int events, void *priv)
Packit cac203
{
Packit cac203
	struct lw_common_port_priv *common_ppriv = priv;
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = priv;
Packit cac203
	struct teamd_port *tdport = common_ppriv->tdport;
Packit cac203
	bool link_up = common_ppriv->link_up;
Packit cac203
	int err;
Packit cac203
Packit cac203
	if (psr_ppriv->reply_received) {
Packit cac203
		link_up = true;
Packit cac203
		psr_ppriv->missed = 0;
Packit cac203
	} else {
Packit cac203
		psr_ppriv->missed++;
Packit cac203
		if (psr_ppriv->missed > psr_ppriv->missed_max && link_up) {
Packit cac203
			teamd_log_dbg(ctx, "%s: Missed %u replies (max %u).",
Packit cac203
				      tdport->ifname, psr_ppriv->missed,
Packit cac203
				      psr_ppriv->missed_max);
Packit cac203
			link_up = false;
Packit cac203
		}
Packit cac203
	}
Packit cac203
	err = teamd_link_watch_check_link_up(ctx, tdport,
Packit cac203
					     common_ppriv, link_up);
Packit cac203
	if (err)
Packit cac203
		return err;
Packit cac203
	psr_ppriv->reply_received = false;
Packit cac203
Packit cac203
	return psr_ppriv->ops->send(psr_ppriv);
Packit cac203
}
Packit cac203
Packit cac203
#define LW_SOCKET_CB_NAME "lw_socket"
Packit cac203
static int lw_psr_callback_socket(struct teamd_context *ctx, int events, void *priv)
Packit cac203
{
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = priv;
Packit cac203
Packit cac203
	return psr_ppriv->ops->receive(psr_ppriv);
Packit cac203
}
Packit cac203
Packit cac203
static int lw_psr_load_options(struct teamd_context *ctx,
Packit cac203
			       struct teamd_port *tdport,
Packit cac203
			       struct lw_psr_port_priv *psr_ppriv)
Packit cac203
{
Packit cac203
	struct teamd_config_path_cookie *cpcookie = psr_ppriv->common.cpcookie;
Packit cac203
	int err;
Packit cac203
	int tmp;
Packit cac203
Packit cac203
	err = teamd_config_int_get(ctx, &tmp, "@.interval", cpcookie);
Packit cac203
	if (!err) {
Packit cac203
		if (tmp < 0) {
Packit cac203
			teamd_log_err("\"interval\" must not be negative number.");
Packit cac203
			return -EINVAL;
Packit cac203
		}
Packit cac203
	} else {
Packit cac203
		tmp = LW_PSR_DEFAULT_INTERVAL;
Packit cac203
	}
Packit cac203
	teamd_log_dbg(ctx, "interval \"%d\".", tmp);
Packit cac203
	ms_to_timespec(&psr_ppriv->interval, tmp);
Packit cac203
Packit cac203
	err = teamd_config_int_get(ctx, &tmp, "@.init_wait", cpcookie);
Packit cac203
	if (!err)
Packit cac203
		ms_to_timespec(&psr_ppriv->init_wait, tmp);
Packit cac203
	/* if init_wait is set to 0, use default_init_wait */
Packit cac203
	if (err || !tmp)
Packit cac203
		psr_ppriv->init_wait = lw_psr_default_init_wait;
Packit cac203
	teamd_log_dbg(ctx, "init_wait \"%d\".", timespec_to_ms(&psr_ppriv->init_wait));
Packit cac203
Packit cac203
	err = teamd_config_int_get(ctx, &tmp, "@.missed_max", cpcookie);
Packit cac203
	if (!err) {
Packit cac203
		if (tmp < 0) {
Packit cac203
			teamd_log_err("\"missed_max\" must not be negative number.");
Packit cac203
			return -EINVAL;
Packit cac203
		}
Packit cac203
	} else {
Packit cac203
		tmp = LW_PSR_DEFAULT_MISSED_MAX;
Packit cac203
	}
Packit cac203
	teamd_log_dbg(ctx, "missed_max \"%d\".", tmp);
Packit cac203
	psr_ppriv->missed_max = tmp;
Packit cac203
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
struct lw_psr_port_priv *
Packit cac203
lw_psr_ppriv_get(struct lw_common_port_priv *common_ppriv)
Packit cac203
{
Packit cac203
	return (struct lw_psr_port_priv *) common_ppriv;
Packit cac203
}
Packit cac203
Packit cac203
Packit cac203
int lw_psr_port_added(struct teamd_context *ctx, struct teamd_port *tdport,
Packit cac203
		      void *priv, void *creator_priv)
Packit cac203
{
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = priv;
Packit cac203
	int err;
Packit cac203
Packit cac203
	err = lw_psr_load_options(ctx, tdport, psr_ppriv);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to load options.");
Packit cac203
		return err;
Packit cac203
	}
Packit cac203
Packit cac203
	err = psr_ppriv->ops->load_options(ctx, tdport, psr_ppriv);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to load options.");
Packit cac203
		return err;
Packit cac203
	}
Packit cac203
Packit cac203
	err = psr_ppriv->ops->sock_open(psr_ppriv);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to create socket.");
Packit cac203
		return err;
Packit cac203
	}
Packit cac203
Packit cac203
	err = teamd_loop_callback_fd_add(ctx, LW_SOCKET_CB_NAME, psr_ppriv,
Packit cac203
					 lw_psr_callback_socket,
Packit cac203
					 psr_ppriv->sock,
Packit cac203
					 TEAMD_LOOP_FD_EVENT_READ);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed add socket callback.");
Packit cac203
		goto close_sock;
Packit cac203
	}
Packit cac203
Packit cac203
	err = teamd_loop_callback_timer_add_set(ctx, LW_PERIODIC_CB_NAME,
Packit cac203
						psr_ppriv,
Packit cac203
						lw_psr_callback_periodic,
Packit cac203
						&psr_ppriv->interval,
Packit cac203
						&psr_ppriv->init_wait);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed add callback timer");
Packit cac203
		goto socket_callback_del;
Packit cac203
	}
Packit cac203
Packit cac203
	err = team_set_port_user_linkup_enabled(ctx->th, tdport->ifindex, true);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("%s: Failed to enable user linkup.",
Packit cac203
			      tdport->ifname);
Packit cac203
		goto periodic_callback_del;
Packit cac203
	}
Packit cac203
Packit cac203
	teamd_loop_callback_enable(ctx, LW_SOCKET_CB_NAME, psr_ppriv);
Packit cac203
	teamd_loop_callback_enable(ctx, LW_PERIODIC_CB_NAME, psr_ppriv);
Packit cac203
	return 0;
Packit cac203
Packit cac203
periodic_callback_del:
Packit cac203
	teamd_loop_callback_del(ctx, LW_PERIODIC_CB_NAME, psr_ppriv);
Packit cac203
socket_callback_del:
Packit cac203
	teamd_loop_callback_del(ctx, LW_SOCKET_CB_NAME, psr_ppriv);
Packit cac203
close_sock:
Packit cac203
	psr_ppriv->ops->sock_close(psr_ppriv);
Packit cac203
	return err;
Packit cac203
}
Packit cac203
Packit cac203
void lw_psr_port_removed(struct teamd_context *ctx, struct teamd_port *tdport,
Packit cac203
			 void *priv, void *creator_priv)
Packit cac203
{
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = priv;
Packit cac203
Packit cac203
	teamd_loop_callback_del(ctx, LW_PERIODIC_CB_NAME, psr_ppriv);
Packit cac203
	teamd_loop_callback_del(ctx, LW_SOCKET_CB_NAME, psr_ppriv);
Packit cac203
	psr_ppriv->ops->sock_close(psr_ppriv);
Packit cac203
}
Packit cac203
Packit cac203
int lw_psr_state_interval_get(struct teamd_context *ctx,
Packit cac203
			      struct team_state_gsc *gsc,
Packit cac203
			      void *priv)
Packit cac203
{
Packit cac203
	struct lw_common_port_priv *common_ppriv = priv;
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = lw_psr_ppriv_get(common_ppriv);
Packit cac203
Packit cac203
	gsc->data.int_val = timespec_to_ms(&psr_ppriv->interval);
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
int lw_psr_state_init_wait_get(struct teamd_context *ctx,
Packit cac203
			       struct team_state_gsc *gsc,
Packit cac203
			       void *priv)
Packit cac203
{
Packit cac203
	struct lw_common_port_priv *common_ppriv = priv;
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = lw_psr_ppriv_get(common_ppriv);
Packit cac203
Packit cac203
	gsc->data.int_val = timespec_to_ms(&psr_ppriv->init_wait);
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
int lw_psr_state_missed_max_get(struct teamd_context *ctx,
Packit cac203
				struct team_state_gsc *gsc,
Packit cac203
				void *priv)
Packit cac203
{
Packit cac203
	struct lw_common_port_priv *common_ppriv = priv;
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = lw_psr_ppriv_get(common_ppriv);
Packit cac203
Packit cac203
	gsc->data.int_val = psr_ppriv->missed_max;
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
int lw_psr_state_missed_get(struct teamd_context *ctx,
Packit cac203
			    struct team_state_gsc *gsc,
Packit cac203
			    void *priv)
Packit cac203
{
Packit cac203
	struct lw_common_port_priv *common_ppriv = priv;
Packit cac203
	struct lw_psr_port_priv *psr_ppriv = lw_psr_ppriv_get(common_ppriv);
Packit cac203
Packit cac203
	gsc->data.int_val = psr_ppriv->missed;
Packit cac203
	return 0;
Packit cac203
}