|
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 |
};
|