Skip to content

Commit c723737

Browse files
committed
teamd: fix possible race in master ifname callback
In teamd the messages from kernel are processed in order: options ifinfo ports However, kernel sends the messages in a different order. See: team_upper_dev_link() which generates ifinfo notification __team_port_change_port_added() which generates ports notification __team_options_change_check() which generates options notification So there is a chance that the teamd processed only the port without options and right after that it processes ifinfo. Fix this by introducing teamd_port_enabled_check() which does not log error and ignore the port in case this call fails. This is safe as this is going to be handled by future link_watch_enabled_option_changed() call. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Fixes: 5f35166 ("teamd: add port_master_ifindex_changed for link_watch_port_watch_ops") Tested-by: Stepan Blyshchak <stepanb@mellanox.com> Reviewed-by: Xin Long <lucien.xin@gmail.com>
1 parent 471fb50 commit c723737

File tree

3 files changed

+31
-8
lines changed

3 files changed

+31
-8
lines changed

teamd/teamd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ int teamd_port_remove_all(struct teamd_context *ctx);
325325
void teamd_port_obj_remove_all(struct teamd_context *ctx);
326326
int teamd_port_enabled(struct teamd_context *ctx, struct teamd_port *tdport,
327327
bool *enabled);
328+
int teamd_port_enabled_check(struct teamd_context *ctx,
329+
struct teamd_port *tdport, bool *enabled);
328330
int teamd_port_prio(struct teamd_context *ctx, struct teamd_port *tdport);
329331
int teamd_port_check_enable(struct teamd_context *ctx,
330332
struct teamd_port *tdport,

teamd/teamd_link_watch.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,16 @@ static int link_watch_refresh_forced_send(struct teamd_context *ctx)
423423
int err;
424424

425425
teamd_for_each_tdport(tdport, ctx) {
426-
err = teamd_port_enabled(ctx, tdport, &port_enabled);
427-
if (err)
428-
return err;
426+
err = teamd_port_enabled_check(ctx, tdport, &port_enabled);
427+
if (err) {
428+
/* Looks like the options are not ready for this port.
429+
* This can happen when called from
430+
* link_watch_port_master_ifindex_changed(). Skip this
431+
* for now, let it be handled by future call of
432+
* link_watch_enabled_option_changed().
433+
*/
434+
continue;
435+
}
429436
__set_forced_send_for_port(tdport, port_enabled);
430437
if (port_enabled)
431438
enabled_port_count++;

teamd/teamd_per_port.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,26 +389,40 @@ int teamd_port_remove_ifname(struct teamd_context *ctx, const char *port_name)
389389
return teamd_port_remove(ctx, tdport);
390390
}
391391

392-
int teamd_port_enabled(struct teamd_context *ctx, struct teamd_port *tdport,
393-
bool *enabled)
392+
int __teamd_port_enabled(struct teamd_context *ctx, struct teamd_port *tdport,
393+
bool *enabled, bool may_fail)
394394
{
395395
struct team_option *option;
396396

397397
option = team_get_option(ctx->th, "np", "enabled", tdport->ifindex);
398398
if (!option) {
399-
teamd_log_err("%s: Failed to find \"enabled\" option.",
400-
tdport->ifname);
399+
if (!may_fail)
400+
teamd_log_err("%s: Failed to find \"enabled\" option.",
401+
tdport->ifname);
401402
return -ENOENT;
402403
}
403404
if (team_get_option_type(option) != TEAM_OPTION_TYPE_BOOL) {
404-
teamd_log_err("Unexpected type of \"enabled\" option.");
405+
if (!may_fail)
406+
teamd_log_err("Unexpected type of \"enabled\" option.");
405407
return -EINVAL;
406408
}
407409

408410
*enabled = team_get_option_value_bool(option);
409411
return 0;
410412
}
411413

414+
int teamd_port_enabled(struct teamd_context *ctx, struct teamd_port *tdport,
415+
bool *enabled)
416+
{
417+
return __teamd_port_enabled(ctx, tdport, enabled, false);
418+
}
419+
420+
int teamd_port_enabled_check(struct teamd_context *ctx,
421+
struct teamd_port *tdport, bool *enabled)
422+
{
423+
return __teamd_port_enabled(ctx, tdport, enabled, true);
424+
}
425+
412426
int teamd_port_prio(struct teamd_context *ctx, struct teamd_port *tdport)
413427
{
414428
int prio;

0 commit comments

Comments
 (0)