The first patch implements the API in libteam to change the carrier from the user space teamd daemon.
The second patch fix lacp mode to set the carrier UP or DOWN depending on the ports state.
The last patch adds a new feature called min_ports. The parameter works as a threshold for the lacp runner to decide whether to set the carrier up or down.
Flavio Leitner (3): libteam: add API for carrier control lacp: fix carrier state lacp: add min_ports parameter
include/team.h | 2 + lib/libteam.c | 55 ++++++++++++++++++++++++ man/teamd.conf.5 | 7 ++++ teamd/teamd_runner_lacp.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+)
Signed-off-by: Flavio Leitner fbl@redhat.com --- include/team.h | 2 ++ lib/libteam.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+)
diff --git a/include/team.h b/include/team.h index d6a5451..207cdd3 100644 --- a/include/team.h +++ b/include/team.h @@ -240,6 +240,8 @@ char *team_ifindex2ifname(struct team_handle *th, uint32_t ifindex, int team_port_add(struct team_handle *th, uint32_t port_ifindex); int team_port_remove(struct team_handle *th, uint32_t port_ifindex); bool team_is_our_port(struct team_handle *th, uint32_t port_ifindex); +int team_carrier_set(struct team_handle *th, bool carrier_up); +bool team_carrier_get(struct team_handle *th); int team_hwaddr_set(struct team_handle *th, uint32_t ifindex, const char *addr, unsigned int addr_len); int team_hwaddr_get(struct team_handle *th, uint32_t ifindex, diff --git a/lib/libteam.c b/lib/libteam.c index 483b815..2590388 100644 --- a/lib/libteam.c +++ b/lib/libteam.c @@ -1233,6 +1233,61 @@ int team_port_remove(struct team_handle *th, uint32_t port_ifindex) }
/** + * team_carrier_set: + * @th: libteam library context + * @ifindex: interface index + * @status: carrier status + * + * Sets carrier status for the master network interface + * + * Returns: zero on success or negative number in case of an error. + **/ +TEAM_EXPORT +int team_carrier_set(struct team_handle *th, bool carrier_up) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_alloc(); + if (!link) + return -ENOMEM; + + rtnl_link_set_ifindex(link, th->ifindex); + rtnl_link_set_carrier(link, carrier_up ? 1 : 0); + + err = rtnl_link_change(th->nl_cli.sock, link, link, 0); + err = -nl2syserr(err); + + rtnl_link_put(link); + return err; +} + +/** + * team_carrier_get: + * @th: libteam library context + * + * Gets carrier status of the master network interface + * + * Returns: zero on success or negative number in case of an error. + **/ +TEAM_EXPORT +bool team_carrier_get(struct team_handle *th) +{ + struct rtnl_link *link; + int carrier; + int err; + + err = rtnl_link_get_kernel(th->nl_cli.sock, th->ifindex, NULL, &link); + if (err) + return -nl2syserr(err); + + carrier = rtnl_link_get_carrier(link); + + rtnl_link_put(link); + return carrier ? true : false; +} + +/** * team_hwaddr_set: * @th: libteam library context * @ifindex: interface index
Fix to bring up or down the master depending on its ports states
Signed-off-by: Flavio Leitner fbl@redhat.com --- teamd/teamd_runner_lacp.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+)
diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c index 6bd6a9b..0763919 100644 --- a/teamd/teamd_runner_lacp.c +++ b/teamd/teamd_runner_lacp.c @@ -108,6 +108,7 @@ static bool lacpdu_check(struct lacpdu *lacpdu) struct lacp { struct teamd_context *ctx; uint32_t selected_aggregator_id; + bool carrier_up; struct { bool active; #define LACP_CFG_DFLT_ACTIVE true @@ -339,6 +340,49 @@ static struct lacp_port *lacp_get_best_port(struct lacp *lacp) return best_lacp_port; }
+static int lacp_set_carrier(struct lacp *lacp, bool carrier_up) +{ + struct teamd_context *ctx = lacp->ctx; + int err; + + if (lacp->carrier_up != carrier_up) { + err = team_carrier_set(ctx->th, carrier_up); + if (err) + return err; + + teamd_log_info("%s: carrier changed to %s\n", ctx->team_devname, + carrier_up ? "UP" : "DOWN" ); + lacp->carrier_up = carrier_up; + } + + return 0; +} + +static int lacp_update_carrier(struct lacp *lacp) +{ + struct teamd_port *tdport; + struct lacp_port *lacp_port; + struct team_option *option; + bool state; + + teamd_for_each_tdport(tdport, lacp->ctx) { + lacp_port = lacp_port_get(lacp, tdport); + option = team_get_option(lacp_port->ctx->th, "np", "enabled", + tdport->ifindex); + if (!option) { + teamd_log_err("%s: Failed to find "enabled" option.", + tdport->ifname); + return -ENOENT; + } + + state = team_get_option_value_bool(option); + if (state) + return lacp_set_carrier(lacp, true); + } + + return lacp_set_carrier(lacp, false); +} + static int lacp_update_selected(struct lacp *lacp) { struct lacp_port *best_lacp_port; @@ -383,6 +427,11 @@ static int lacp_update_selected(struct lacp *lacp) if (err) return err; } + + err = lacp_update_carrier(lacp); + if (err) + return err; + return 0; }
@@ -936,6 +985,37 @@ static const struct teamd_event_watch_ops lacp_port_watch_ops = { .port_changed = lacp_event_watch_port_changed, };
+static int lacp_carrier_init(struct teamd_context *ctx, struct lacp *lacp) +{ + int err; + + /* initialize carrier control */ + err = team_carrier_set(ctx->th, false); + if (err) { + teamd_log_err("Failed to set carrier down."); + return err; + } + + lacp->carrier_up = false; + + return 0; +} + +static int lacp_carrier_fini(struct teamd_context *ctx, struct lacp *lacp) +{ + int err; + + err = team_carrier_set(ctx->th, false); + if (err) { + teamd_log_err("Failed to set carrier down."); + return err; + } + + lacp->carrier_up = false; + + return 0; +} + static int lacp_init(struct teamd_context *ctx) { struct lacp *lacp = ctx->runner_priv; @@ -955,6 +1035,11 @@ static int lacp_init(struct teamd_context *ctx) teamd_log_err("Failed to load config values."); return err; } + err = lacp_carrier_init(ctx, lacp); + if (err) { + teamd_log_err("Failed to initialize carrier."); + return err; + } err = teamd_event_watch_register(ctx, &lacp_port_watch_ops, lacp); if (err) { teamd_log_err("Failed to register event watch."); @@ -977,6 +1062,7 @@ static void lacp_fini(struct teamd_context *ctx)
teamd_balancer_fini(lacp->tb); teamd_event_watch_unregister(ctx, &lacp_port_watch_ops, lacp); + lacp_carrier_fini(ctx, lacp); }
static json_t *__fill_lacpdu_info(struct lacpdu_info *lacpdu_info)
This parameter works as a threshold for the lacp runner to decide whether to set the carrier up or down.
Signed-off-by: Flavio Leitner fbl@redhat.com --- man/teamd.conf.5 | 7 +++++++ teamd/teamd_runner_lacp.c | 20 +++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/man/teamd.conf.5 b/man/teamd.conf.5 index 06beb2e..f826f7b 100644 --- a/man/teamd.conf.5 +++ b/man/teamd.conf.5 @@ -120,6 +120,13 @@ System priority, value can be 0-65535. Default: .BR "255"
+.TP +.BR "runner.min_ports " (int) +Specifies the minimum number of ports that must be active before asserting carrier in the master interface, value can be 1-255. + +Default: +.BR "0" + .SH ETHTOOL LINK WATCH SPECIFIC OPTIONS .TP .BR "link_watch.delay_up "| " ports.PORTIFNAME.link_watch.delay_up " (int) diff --git a/teamd/teamd_runner_lacp.c b/teamd/teamd_runner_lacp.c index 0763919..a2cee33 100644 --- a/teamd/teamd_runner_lacp.c +++ b/teamd/teamd_runner_lacp.c @@ -116,6 +116,8 @@ struct lacp { #define LACP_CFG_DFLT_SYS_PRIO 0xffff bool fast_rate; #define LACP_CFG_DFLT_FAST_RATE false + int min_ports; +#define LACP_CFG_DFLT_MIN_PORTS 1 } cfg; struct teamd_balancer *tb; }; @@ -196,6 +198,19 @@ static int lacp_load_config(struct teamd_context *ctx, struct lacp *lacp) &tmp); lacp->cfg.fast_rate = err ? LACP_CFG_DFLT_FAST_RATE : !!tmp; teamd_log_dbg("Using fast_rate "%d".", lacp->cfg.fast_rate); + + err = json_unpack(ctx->config_json, "{s:{s:i}}", "runner", "min_ports", + &tmp); + if (err) { + lacp->cfg.min_ports = LACP_CFG_DFLT_MIN_PORTS; + } else if (tmp < 1 || tmp > UCHAR_MAX) { + teamd_log_err(""min_ports" value is out of its limits."); + return -EINVAL; + } else { + lacp->cfg.min_ports = tmp; + } + teamd_log_dbg("Using min_ports "%d".", lacp->cfg.min_ports); + return 0; }
@@ -363,8 +378,10 @@ static int lacp_update_carrier(struct lacp *lacp) struct teamd_port *tdport; struct lacp_port *lacp_port; struct team_option *option; + int ports_enabled; bool state;
+ ports_enabled = 0; teamd_for_each_tdport(tdport, lacp->ctx) { lacp_port = lacp_port_get(lacp, tdport); option = team_get_option(lacp_port->ctx->th, "np", "enabled", @@ -376,8 +393,9 @@ static int lacp_update_carrier(struct lacp *lacp) }
state = team_get_option_value_bool(option); - if (state) + if (state && ++ports_enabled >= lacp->cfg.min_ports) return lacp_set_carrier(lacp, true); + }
return lacp_set_carrier(lacp, false);
libteam@lists.fedorahosted.org