Blame teamd/teamd_runner_loadbalance.c

Packit cac203
/*
Packit cac203
 *   teamd_runner_loadbalance.c - Load-balancing runners
Packit cac203
 *   Copyright (C) 2012-2015 Jiri Pirko <jiri@resnulli.us>
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 <sys/socket.h>
Packit cac203
#include <linux/netdevice.h>
Packit cac203
#include <team.h>
Packit cac203
Packit cac203
#include "teamd.h"
Packit cac203
Packit cac203
struct lb {
Packit cac203
	struct teamd_balancer *tb;
Packit cac203
};
Packit cac203
Packit cac203
static int lb_event_watch_port_added(struct teamd_context *ctx,
Packit cac203
				     struct teamd_port *tdport, void *priv)
Packit cac203
{
Packit cac203
	struct lb *lb = priv;
Packit cac203
	int err;
Packit cac203
Packit cac203
	err = team_hwaddr_set(ctx->th, tdport->ifindex, ctx->hwaddr,
Packit cac203
			      ctx->hwaddr_len);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to set port \"%s\" hardware address. ",
Packit cac203
			      tdport->ifname);
Packit cac203
		return err;
Packit cac203
	}
Packit cac203
Packit cac203
	if (!team_is_port_link_up(tdport->team_port)) {
Packit cac203
		err = team_set_port_enabled(ctx->th, tdport->ifindex, false);
Packit cac203
		if (err) {
Packit cac203
			teamd_log_err("%s: Failed to disable port.",
Packit cac203
				      tdport->ifname);
Packit cac203
			return TEAMD_ENOENT(err) ? 0 : err;
Packit cac203
		}
Packit cac203
	}
Packit cac203
	return teamd_balancer_port_added(lb->tb, tdport);
Packit cac203
}
Packit cac203
Packit cac203
static void lb_event_watch_port_removed(struct teamd_context *ctx,
Packit cac203
					struct teamd_port *tdport, void *priv)
Packit cac203
{
Packit cac203
	struct lb *lb = priv;
Packit cac203
Packit cac203
	teamd_balancer_port_removed(lb->tb, tdport);
Packit cac203
}
Packit cac203
Packit cac203
static int lb_event_watch_port_link_changed(struct teamd_context *ctx,
Packit cac203
					    struct teamd_port *tdport,
Packit cac203
					    void *priv)
Packit cac203
{
Packit cac203
	bool port_up = teamd_link_watch_port_up(ctx, tdport);
Packit cac203
Packit cac203
	return teamd_port_check_enable(ctx, tdport, port_up, !port_up);
Packit cac203
}
Packit cac203
Packit cac203
static int lb_event_watch_hwaddr_changed(struct teamd_context *ctx, void *priv)
Packit cac203
{
Packit cac203
	struct teamd_port *tdport;
Packit cac203
	int err;
Packit cac203
Packit cac203
	teamd_for_each_tdport(tdport, ctx) {
Packit cac203
		err = team_hwaddr_set(ctx->th, tdport->ifindex, ctx->hwaddr,
Packit cac203
				      ctx->hwaddr_len);
Packit cac203
		if (err) {
Packit cac203
			teamd_log_err("%s: Failed to set port hardware address.",
Packit cac203
				      tdport->ifname);
Packit cac203
			return err;
Packit cac203
		}
Packit cac203
	}
Packit cac203
Packit cac203
	return 0;
Packit cac203
}
Packit cac203
Packit cac203
static int lb_event_watch_port_hwaddr_changed(struct teamd_context *ctx,
Packit cac203
					      struct teamd_port *tdport,
Packit cac203
					      void *priv)
Packit cac203
{
Packit cac203
	int err;
Packit cac203
Packit cac203
	if (!teamd_port_present(ctx, tdport))
Packit cac203
		return 0;
Packit cac203
Packit cac203
	if (!memcmp(team_get_ifinfo_hwaddr(tdport->team_ifinfo),
Packit cac203
		    ctx->hwaddr, ctx->hwaddr_len))
Packit cac203
		return 0;
Packit cac203
Packit cac203
	err = team_hwaddr_set(ctx->th, tdport->ifindex, ctx->hwaddr,
Packit cac203
			      ctx->hwaddr_len);
Packit cac203
	if (err)
Packit cac203
		teamd_log_err("%s: Failed to set port hardware address.",
Packit cac203
			      tdport->ifname);
Packit cac203
Packit cac203
	return err;
Packit cac203
}
Packit cac203
Packit cac203
static int lb_event_watch_enabled_option_changed(struct teamd_context *ctx,
Packit cac203
						 struct team_option *option,
Packit cac203
						 void *priv)
Packit cac203
{
Packit cac203
	struct teamd_port *tdport;
Packit cac203
Packit cac203
	tdport = teamd_get_port(ctx, team_get_option_port_ifindex(option));
Packit cac203
	if (!tdport)
Packit cac203
		return 0;
Packit cac203
Packit cac203
	return lb_event_watch_port_link_changed(ctx, tdport, priv);
Packit cac203
}
Packit cac203
Packit cac203
static const struct teamd_event_watch_ops lb_port_watch_ops = {
Packit cac203
	.hwaddr_changed = lb_event_watch_hwaddr_changed,
Packit cac203
	.port_hwaddr_changed = lb_event_watch_port_hwaddr_changed,
Packit cac203
	.port_added = lb_event_watch_port_added,
Packit cac203
	.port_removed = lb_event_watch_port_removed,
Packit cac203
	.port_link_changed = lb_event_watch_port_link_changed,
Packit cac203
	.option_changed = lb_event_watch_enabled_option_changed,
Packit cac203
	.option_changed_match_name = "enabled",
Packit cac203
};
Packit cac203
Packit cac203
static int lb_init(struct teamd_context *ctx, void *priv)
Packit cac203
{
Packit cac203
	struct lb *lb = priv;
Packit cac203
	int err;
Packit cac203
Packit cac203
	err = teamd_hash_func_set(ctx);
Packit cac203
	if (err)
Packit cac203
		return err;
Packit cac203
	err = teamd_event_watch_register(ctx, &lb_port_watch_ops, lb);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to register event watch.");
Packit cac203
		return err;
Packit cac203
	}
Packit cac203
	err = teamd_balancer_init(ctx, &lb->tb);
Packit cac203
	if (err) {
Packit cac203
		teamd_log_err("Failed to init balanced.");
Packit cac203
		goto event_watch_unregister;
Packit cac203
	}
Packit cac203
	return 0;
Packit cac203
event_watch_unregister:
Packit cac203
	teamd_event_watch_unregister(ctx, &lb_port_watch_ops, lb);
Packit cac203
	return err;
Packit cac203
}
Packit cac203
Packit cac203
static void lb_fini(struct teamd_context *ctx, void *priv)
Packit cac203
{
Packit cac203
	struct lb *lb = priv;
Packit cac203
Packit cac203
	teamd_balancer_fini(lb->tb);
Packit cac203
	teamd_event_watch_unregister(ctx, &lb_port_watch_ops, lb);
Packit cac203
}
Packit cac203
Packit cac203
const struct teamd_runner teamd_runner_loadbalance = {
Packit cac203
	.name		= "loadbalance",
Packit cac203
	.team_mode_name	= "loadbalance",
Packit cac203
	.init		= lb_init,
Packit cac203
	.fini		= lb_fini,
Packit cac203
	.priv_size	= sizeof(struct lb),
Packit cac203
};